This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to exclude
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally. I wanted to avoid
situation when a lot of #ifdef CONFIG_CPU_FREQ_BOOST are scattered at
cpufreq code (especially cpufreq.c large file)
- Only one cpufreq_boost instance is created at cpufreq driver file.
- Boost can manage overclocking when many policies are istalled in
the system (this is a preparation for b.L)
- Boost sysfs attributies are seen only when cpufreq driver supports them.
They will not show up until either CONFIG_CPU_FREQ_BOOST or device tree
cpufreq "boost_mode" attribute is defined.
- No special spin_lock for Boost was created. The one from cpufreq was
reused.
- Low level boost trigger function (*low_level_boost function callback) is
necessary to "glue" together acpi-cpufreq boost with software based one.
Tested at: HW: Exynos 4412 3.10 linux
Compile tested x86_64 defconfig (acpi) - help with HW test
needed
Lukasz Majewski (5):
cpufreq: Define cpufreq_set_drv_attr_files() to add per CPU sysfs
attributes
cpufreq:boost: Add support for software based CPU frequency boost
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
cpufreq:exynos:Extend exynos cpufreq driver to support boost
cpufreq:boost:Kconfig: Enable boost support at Kconfig
drivers/cpufreq/Kconfig | 7 ++
drivers/cpufreq/acpi-cpufreq.c | 64 ++++++--------
drivers/cpufreq/cpufreq.c | 175 ++++++++++++++++++++++++++++++++++++--
drivers/cpufreq/exynos-cpufreq.c | 48 +++++++++++
drivers/cpufreq/freq_table.c | 87 ++++++++++++++++++-
include/linux/cpufreq.h | 35 +++++++-
6 files changed, 369 insertions(+), 47 deletions(-)
--
1.7.10.4
The cpufreq_set_drv_attr_files() function creates sysfs file entry for
each available CPU. With it in place it is possible to add different
set of attributes without code duplication.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
drivers/cpufreq/cpufreq.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1b8a48e..ca74e27 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -730,12 +730,23 @@ static int cpufreq_add_dev_symlink(unsigned int cpu,
return ret;
}
+static int cpufreq_set_drv_attr_files(struct cpufreq_policy *policy,
+ struct freq_attr **drv_attr)
+{
+ while ((drv_attr) && (*drv_attr)) {
+ if (sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)))
+ return 1;
+ drv_attr++;
+ }
+
+ return 0;
+}
+
static int cpufreq_add_dev_interface(unsigned int cpu,
struct cpufreq_policy *policy,
struct device *dev)
{
struct cpufreq_policy new_policy;
- struct freq_attr **drv_attr;
unsigned long flags;
int ret = 0;
unsigned int j;
@@ -747,13 +758,9 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
return ret;
/* set up files for this cpu device */
- drv_attr = cpufreq_driver->attr;
- while ((drv_attr) && (*drv_attr)) {
- ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
- if (ret)
- goto err_out_kobj_put;
- drv_attr++;
- }
+ if (cpufreq_set_drv_attr_files(policy, cpufreq_driver->attr))
+ goto err_out_kobj_put;
+
if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (ret)
--
1.7.10.4
This commit adds support for software based frequency boosting.
Exynos4 SoCs (e.g. 4x12) allow setting of frequency above its normal
condition limits. This can be done for some short time.
Overclocking (boost) support came from cpufreq driver (which is platform
dependent). Hence the data structure describing it is defined at its file.
To allow support for either SW and HW (Intel) based boosting, the cpufreq
core code has been extended to support both solutions.
The main boost switch has been put at /sys/devices/system/cpu/cpufreq/boost.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
drivers/cpufreq/cpufreq.c | 156 ++++++++++++++++++++++++++++++++++++++++++
drivers/cpufreq/freq_table.c | 87 ++++++++++++++++++++++-
include/linux/cpufreq.h | 35 +++++++++-
3 files changed, 275 insertions(+), 3 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index ca74e27..8cf9a92 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -133,6 +133,11 @@ bool have_governor_per_policy(void)
return cpufreq_driver->have_governor_per_policy;
}
+/**
+ * Global definition of cpufreq_boost structure
+ */
+struct cpufreq_boost *cpufreq_boost;
+
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
{
struct cpufreq_policy *data;
@@ -315,6 +320,45 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost_status(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpufreq_boost *boost = cpufreq_boost;
+
+ if (!boost)
+ return -ENODEV;
+
+ return sprintf(buf, "%d\n", boost->status);
+}
+
+static ssize_t store_boost_status(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cpufreq_boost *boost = cpufreq_boost;
+ struct cpufreq_policy *p;
+ int ret, enable;
+
+ if (!boost)
+ return -ENODEV;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ /* Adjust all policies to support boost */
+ list_for_each_entry(p, &boost->policies, boost_list)
+ if (cpufreq_boost_trigger_state(p, enable)) {
+ pr_err("Cannot %sable boost (policy 0x%p)!\n",
+ enable ? "en" : "dis", p);
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static struct global_attr global_boost = __ATTR(boost, 0644,
+ show_boost_status,
+ store_boost_status);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -761,6 +805,18 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
if (cpufreq_set_drv_attr_files(policy, cpufreq_driver->attr))
goto err_out_kobj_put;
+ if (cpufreq_driver->boost) {
+ if (sysfs_create_file(cpufreq_global_kobject,
+ &(global_boost.attr)))
+ pr_warn("could not register global boost sysfs file\n");
+ else
+ pr_debug("registered global boost sysfs file\n");
+
+ if (cpufreq_set_drv_attr_files(policy,
+ cpufreq_driver->boost->attr))
+ goto err_out_kobj_put;
+ }
+
if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (ret)
@@ -923,6 +979,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
+ cpufreq_boost_init(policy);
+
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -1860,6 +1918,100 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+int cpufreq_boost_trigger_state(struct cpufreq_policy *policy, int state)
+{
+ struct cpufreq_boost *boost;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!policy || !policy->boost || !policy->boost->low_level_boost)
+ return -ENODEV;
+
+ boost = policy->boost;
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+
+ if (boost->status != state) {
+ policy->boost->status = state;
+ ret = boost->low_level_boost(policy, state);
+ if (ret) {
+ pr_err("BOOST cannot %sable low level code (%d)\n",
+ state ? "en" : "dis", ret);
+ return ret;
+ }
+ }
+
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_debug("cpufreq BOOST %sabled\n", state ? "en" : "dis");
+
+ return 0;
+}
+
+/**
+ * cpufreq_boost_notifier - notifier callback for cpufreq policy change.
+ * <at> nb: struct notifier_block * with callback info.
+ * <at> event: value showing cpufreq event for which this function invoked.
+ * <at> data: callback-specific data
+ */
+static int cpufreq_boost_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+
+ if (event == CPUFREQ_INCOMPATIBLE) {
+ if (!policy || !policy->boost)
+ return -ENODEV;
+
+ if (policy->boost->status == CPUFREQ_BOOST_EN) {
+ pr_info("NOTIFIER BOOST: MAX: %d e:%lu cpu: %d\n",
+ policy->max, event, policy->cpu);
+ cpufreq_boost_trigger_state(policy, 0);
+ }
+ }
+
+ return 0;
+}
+
+/* Notifier for cpufreq policy change */
+static struct notifier_block cpufreq_boost_notifier_block = {
+ .notifier_call = cpufreq_boost_notifier,
+};
+
+int cpufreq_boost_init(struct cpufreq_policy *policy)
+{
+ int ret = 0;
+
+ if (!policy)
+ return -EINVAL;
+
+ if (!cpufreq_driver->boost) {
+ pr_err("Boost mode not supported on this device\n");
+ return -ENODEV;
+ }
+
+ policy->boost = cpufreq_boost = cpufreq_driver->boost;
+
+ /* disable boost for newly created policy - as we e.g. change
+ governor */
+ policy->boost->status = CPUFREQ_BOOST_DIS;
+
+ /* register policy notifier */
+ ret = cpufreq_register_notifier(&cpufreq_boost_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ if (ret) {
+ pr_err("CPUFREQ BOOST notifier not registered.\n");
+ return ret;
+ }
+ /* add policy to policies list headed at struct cpufreq_boost */
+ list_add_tail(&policy->boost_list, &cpufreq_boost->policies);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_init);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -1954,6 +2106,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+
+ if (cpufreq_driver->boost)
+ sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a7966..0e95524 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 2002 - 2003 Dominik Brodowski
*
+ * Copyright (C) 2013 Lukasz Majewski <[email protected]>
+ *
* 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.
@@ -20,6 +22,36 @@
* FREQUENCY TABLE HELPERS *
*********************************************************************/
+/*********************************************************************
+ * BOOST FREQ HELPERS *
+ *********************************************************************/
+static int cpufreq_frequency_table_skip_boost(struct cpufreq_policy *policy,
+ unsigned int index)
+{
+ if (index == CPUFREQ_BOOST)
+ if (!policy->boost ||
+ policy->boost->status == CPUFREQ_BOOST_DIS)
+ return 1;
+
+ return 0;
+}
+
+unsigned int
+cpufreq_frequency_table_boost_max(struct cpufreq_frequency_table *freq_table)
+{
+ int index, boost_freq_max;
+
+ for (index = 0, boost_freq_max = 0;
+ freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
+ if (freq_table[index].index == CPUFREQ_BOOST) {
+ if (freq_table[index].frequency > boost_freq_max)
+ boost_freq_max = freq_table[index].frequency;
+ }
+
+ return boost_freq_max;
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_boost_max);
+
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
@@ -34,6 +66,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (cpufreq_frequency_table_skip_boost(policy,
+ table[i].index))
+ continue;
+
pr_debug("table entry %u: %u kHz, %u index\n",
i, freq, table[i].index);
if (freq < min_freq)
@@ -70,6 +106,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
+ if (cpufreq_frequency_table_skip_boost(policy,
+ table[i].index))
+ continue;
if ((freq >= policy->min) && (freq <= policy->max))
count++;
else if ((next_larger > freq) && (freq > policy->max))
@@ -122,6 +161,9 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
+ if (cpufreq_frequency_table_skip_boost(policy,
+ table[i].index))
+ continue;
if ((freq < policy->min) || (freq > policy->max))
continue;
switch (relation) {
@@ -167,11 +209,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
+#define CPUFREQ_SHOW_NORMAL 0
+#define CPUFREQ_SHOW_BOOST 1
+
static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ int show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,22 +232,59 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+
+ if (show_boost) {
+ if (table[i].index != CPUFREQ_BOOST)
+ continue;
+ } else {
+ if (cpufreq_frequency_table_skip_boost(policy,
+ table[i].index))
+ continue;
+ }
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
return count;
+}
+/**
+ * show_available_normal_freqs - show normal boost frequencies for
+ * the specified CPU
+ */
+static ssize_t show_available_normal_freqs(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, CPUFREQ_SHOW_NORMAL);
}
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
.attr = { .name = "scaling_available_frequencies",
.mode = 0444,
},
- .show = show_available_freqs,
+ .show = show_available_normal_freqs,
};
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t show_available_boost_freqs(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, CPUFREQ_SHOW_BOOST);
+}
+
+struct freq_attr cpufreq_freq_attr_boost_available_freqs = {
+ .attr = { .name = "scaling_boost_frequencies",
+ .mode = 0444,
+ },
+ .show = show_available_boost_freqs,
+};
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_boost_available_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 037d36a..1294c8c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -88,6 +88,25 @@ struct cpufreq_real_policy {
struct cpufreq_governor *governor; /* see below */
};
+#define CPUFREQ_BOOST_DIS (0)
+#define CPUFREQ_BOOST_EN (1)
+
+struct cpufreq_policy;
+struct cpufreq_boost {
+ unsigned int max_boost_freq; /* maximum value of
+ * boosted freq */
+ unsigned int max_normal_freq; /* non boost max freq */
+ int status; /* status of boost */
+
+ /* boost sysfs attributies */
+ struct freq_attr **attr;
+
+ /* low-level trigger for boost */
+ int (*low_level_boost) (struct cpufreq_policy *policy, int state);
+
+ struct list_head policies;
+};
+
struct cpufreq_policy {
/* CPUs sharing clock, require sw coordination */
cpumask_var_t cpus; /* Online CPUs only */
@@ -113,6 +132,9 @@ struct cpufreq_policy {
struct cpufreq_real_policy user_policy;
+ struct cpufreq_boost *boost;
+ struct list_head boost_list;
+
struct kobject kobj;
struct completion kobj_unregister;
};
@@ -262,6 +284,9 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ struct cpufreq_boost *boost;
};
/* flags */
@@ -277,7 +302,6 @@ struct cpufreq_driver {
int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
-
void cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state);
@@ -403,6 +427,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST ~2
+
struct cpufreq_frequency_table {
unsigned int index; /* any */
unsigned int frequency; /* kHz - doesn't need to be in ascending
@@ -421,11 +448,17 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+unsigned int
+cpufreq_frequency_table_boost_max(struct cpufreq_frequency_table *freq_table);
+int cpufreq_boost_init(struct cpufreq_policy *policy);
+
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
+int cpufreq_boost_trigger_state(struct cpufreq_policy *policy, int state);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_boost_available_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
Enable/disable support for BOOST. New flag - CPU_FREQ_BOOST has been
defined for that.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
drivers/cpufreq/Kconfig | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index a1488f5..1007c5e 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,13 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST
+ bool "CPU frequency boost support"
+ help
+ Switch to enable support for frequency boost
+
+ If in doubt, say N.
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
--
1.7.10.4
The Intel's HW based boost solution needs to cooperate with common cpufreq
boost.
For this reason the sysfs handling code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq.c code.
The _store_boost() function has been redesigned to be used as low_level_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
drivers/cpufreq/acpi-cpufreq.c | 64 ++++++++++++++++------------------------
1 file changed, 26 insertions(+), 38 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 11b8b4b..2c95540 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -133,20 +133,10 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(struct cpufreq_policy *policy, int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
+ return 0;
get_online_cpus();
@@ -157,30 +147,31 @@ static ssize_t _store_boost(const char *buf, size_t count)
boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
+ return 0;
}
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_boost(const char *buf, size_t count)
{
- return _store_boost(buf, count);
-}
+ int ret;
+ unsigned long val = 0;
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
-}
+ if (!boost_supported)
+ return -EINVAL;
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost(NULL, (int) val);
+
+ return count;
+}
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
@@ -910,6 +901,11 @@ static struct freq_attr *acpi_cpufreq_attr[] = {
NULL,
};
+static struct cpufreq_boost acpi_boost = {
+ .low_level_boost = _store_boost,
+ .policies = LIST_HEAD_INIT(acpi_boost.policies),
+};
+
static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = acpi_cpufreq_verify,
.target = acpi_cpufreq_target,
@@ -920,6 +916,9 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
+#ifdef CONFIG_CPU_FREQ_BOOST
+ .boost = &acpi_boost,
+#endif
};
static void __init acpi_cpufreq_boost_init(void)
@@ -941,22 +940,11 @@ static void __init acpi_cpufreq_boost_init(void)
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (sysfs_create_file(cpufreq_global_kobject, &(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
--
1.7.10.4
New structure - exynos_boost has been created to embrace the information
related to boost support.
The CONFIG_CPU_FREQ_BOOST flag is responsible for attaching the boost structure
to the cpufreq driver.
Setting exynos cpufreq driver .boost field to NULL, indicates that boost is
not supported.
Moreover device tree attribute "boost_mode" defines if exynos platform
support frequency overclocking (boost).
Moreover new attribute structure describing extra CPU features supported when boost
is enabled is also provided.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
drivers/cpufreq/exynos-cpufreq.c | 48 ++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 3197d88..0b6fdf6 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -267,6 +267,38 @@ static struct freq_attr *exynos_cpufreq_attr[] = {
NULL,
};
+/* per CPU boost attributes to be exported to sysfs */
+static struct freq_attr *exynos_cpufreq_boost_attr[] = {
+ &cpufreq_freq_attr_boost_available_freqs,
+ NULL,
+};
+
+/* low level code to enable/disable boost */
+static int
+exynos_cpufreq_boost_trigger(struct cpufreq_policy *policy, int state)
+{
+
+ if (!policy || !policy->boost)
+ return -ENODEV;
+
+ if (state) {
+ policy->boost->max_normal_freq = policy->max;
+ policy->max = policy->boost->max_boost_freq;
+ policy->cpuinfo.max_freq = policy->max;
+ } else {
+ policy->max = policy->boost->max_normal_freq;
+ policy->cpuinfo.max_freq = policy->max;
+ }
+
+ return 0;
+}
+
+static struct cpufreq_boost exynos_boost = {
+ .attr = exynos_cpufreq_boost_attr,
+ .low_level_boost = exynos_cpufreq_boost_trigger,
+ .policies = LIST_HEAD_INIT(exynos_boost.policies),
+};
+
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
.verify = exynos_verify_speed,
@@ -276,6 +308,9 @@ static struct cpufreq_driver exynos_driver = {
.exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
.attr = exynos_cpufreq_attr,
+#ifdef CONFIG_CPU_FREQ_BOOST
+ .boost = &exynos_boost,
+#endif
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
@@ -359,6 +394,8 @@ static struct of_device_id exynos_cpufreq_of_match[] __initconst = {
static int __init exynos_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
+
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -390,6 +427,17 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
goto err_vdd_arm;
}
+ /* If boost_mode property not available - then NULL out the boost
+ pointer to indicate thst boost is not supported*/
+ if (exynos_driver.boost) {
+ if (of_property_read_bool(node, "boost_mode"))
+ exynos_boost.max_boost_freq =
+ cpufreq_frequency_table_boost_max(
+ exynos_info->freq_table);
+ else
+ exynos_driver.boost = NULL;
+ }
+
locking_frequency = exynos_getspeed(0);
register_pm_notifier(&exynos_cpufreq_nb);
--
1.7.10.4
On 6 June 2013 12:37, Lukasz Majewski <[email protected]> wrote:
> Subject: cpufreq: Define cpufreq_set_drv_attr_files() to add per CPU sysfs attributes
Its not per-cpu. We just add it for policy->cpu and other routines
actually create links.
> The cpufreq_set_drv_attr_files() function creates sysfs file entry for
> each available CPU. With it in place it is possible to add different
> set of attributes without code duplication.
Not for each available cpu but are linked to a policy->kobj and so
shows up on each policy->cpus.
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
> ---
> drivers/cpufreq/cpufreq.c | 23 +++++++++++++++--------
> 1 file changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 1b8a48e..ca74e27 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -730,12 +730,23 @@ static int cpufreq_add_dev_symlink(unsigned int cpu,
> return ret;
> }
>
> +static int cpufreq_set_drv_attr_files(struct cpufreq_policy *policy,
> + struct freq_attr **drv_attr)
> +{
> + while ((drv_attr) && (*drv_attr)) {
> + if (sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)))
> + return 1;
You are changing the semantics here. We used to return error
value from sysfs_create_file() and you are returning 1.
> + drv_attr++;
If drv_attr was valid initially, then drv_attr++ can't make it NULL.
So, we don't need to check validity of drv_attr for every loop.
Hi Viresh,
> On 6 June 2013 12:37, Lukasz Majewski <[email protected]> wrote:
>
> > Subject: cpufreq: Define cpufreq_set_drv_attr_files() to add per
> > CPU sysfs attributes
>
> Its not per-cpu. We just add it for policy->cpu and other routines
> actually create links.
>
> > The cpufreq_set_drv_attr_files() function creates sysfs file entry
> > for each available CPU. With it in place it is possible to add
> > different set of attributes without code duplication.
>
> Not for each available cpu but are linked to a policy->kobj and so
> shows up on each policy->cpus.
Yes, you are right here. Thanks for detailed explanation. Being
"per-cpu" comes from kobj embedded at policy, which has information
about cpus affected.
>
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> > ---
> > drivers/cpufreq/cpufreq.c | 23 +++++++++++++++--------
> > 1 file changed, 15 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 1b8a48e..ca74e27 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -730,12 +730,23 @@ static int cpufreq_add_dev_symlink(unsigned
> > int cpu, return ret;
> > }
> >
> > +static int cpufreq_set_drv_attr_files(struct cpufreq_policy
> > *policy,
> > + struct freq_attr **drv_attr)
> > +{
> > + while ((drv_attr) && (*drv_attr)) {
> > + if (sysfs_create_file(&policy->kobj,
> > &((*drv_attr)->attr)))
> > + return 1;
>
> You are changing the semantics here. We used to return error
> value from sysfs_create_file() and you are returning 1.
Yes, correct. The ret from sysfs_create_file shall be returned.
Returning 1 causes information lost.
>
> > + drv_attr++;
>
> If drv_attr was valid initially, then drv_attr++ can't make it NULL.
> So, we don't need to check validity of drv_attr for every loop.
I'm confused here.
So you want to check dev_attr for NULL just after:
drv_attr = cpufreq_driver->attr;
if (!drv_attr)
goto error;
and skip the check at the while loop:
while ((drv_attr) && (*drv_attr))
to
while ((*drv_attr))
Am I correct?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 6 June 2013 14:28, Lukasz Majewski <[email protected]> wrote:
> I'm confused here.
>
> So you want to check dev_attr for NULL just after:
> drv_attr = cpufreq_driver->attr;
> if (!drv_attr)
> goto error;
>
> and skip the check at the while loop:
> while ((drv_attr) && (*drv_attr))
>
> to
>
> while ((*drv_attr))
>
> Am I correct?
Bingo!!
Hi Viresh,
> On 6 June 2013 14:28, Lukasz Majewski <[email protected]> wrote:
> > I'm confused here.
> >
> > So you want to check dev_attr for NULL just after:
> > drv_attr = cpufreq_driver->attr;
> > if (!drv_attr)
> > goto error;
> >
> > and skip the check at the while loop:
> > while ((drv_attr) && (*drv_attr))
> >
> > to
> >
> > while ((*drv_attr))
> >
> > Am I correct?
>
> Bingo!!
Ok, no problem :-)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Hi,
On 6 June 2013 12:37, Lukasz Majewski <[email protected]> wrote:
> This commit adds support for software based frequency boosting.
> Exynos4 SoCs (e.g. 4x12) allow setting of frequency above its normal
> condition limits. This can be done for some short time.
>
> Overclocking (boost) support came from cpufreq driver (which is platform
> dependent). Hence the data structure describing it is defined at its file.
>
> To allow support for either SW and HW (Intel) based boosting, the cpufreq
> core code has been extended to support both solutions.
>
> The main boost switch has been put at /sys/devices/system/cpu/cpufreq/boost.
Log requires some better paragraphs but I am not concerned about it for now.
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
> ---
> drivers/cpufreq/cpufreq.c | 156 ++++++++++++++++++++++++++++++++++++++++++
> drivers/cpufreq/freq_table.c | 87 ++++++++++++++++++++++-
> include/linux/cpufreq.h | 35 +++++++++-
> 3 files changed, 275 insertions(+), 3 deletions(-)
My initial view on this patch is: "It is overly engineered and needs
to get simplified"
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index ca74e27..8cf9a92 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -133,6 +133,11 @@ bool have_governor_per_policy(void)
> return cpufreq_driver->have_governor_per_policy;
> }
>
> +/**
> + * Global definition of cpufreq_boost structure
> + */
> +struct cpufreq_boost *cpufreq_boost;
Probably just a 'static bool' here cpufreq_boost_enabled. Which takes
care of selection from sysfs.
> static struct cpufreq_governor *__find_governor(const char *str_governor)
> {
> @@ -761,6 +805,18 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
> if (cpufreq_set_drv_attr_files(policy, cpufreq_driver->attr))
> goto err_out_kobj_put;
>
> + if (cpufreq_driver->boost) {
> + if (sysfs_create_file(cpufreq_global_kobject,
> + &(global_boost.attr)))
This will report error for systems where we have two policy structures.
As we are creating something already present.
> + pr_warn("could not register global boost sysfs file\n");
> + else
> + pr_debug("registered global boost sysfs file\n");
Please make all your prints to print function name too:
pr_debug("%s: foo\n", __func__, foo);
> + if (cpufreq_set_drv_attr_files(policy,
> + cpufreq_driver->boost->attr))
Why is this required? Why do we want platforms to add some files
in sysfs?
> /*********************************************************************
> + * BOOST *
> + *********************************************************************/
> +int cpufreq_boost_trigger_state(struct cpufreq_policy *policy, int state)
> +{
> + struct cpufreq_boost *boost;
> + unsigned long flags;
> + int ret = 0;
> +
> + if (!policy || !policy->boost || !policy->boost->low_level_boost)
> + return -ENODEV;
> +
> + boost = policy->boost;
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> +
> + if (boost->status != state) {
> + policy->boost->status = state;
> + ret = boost->low_level_boost(policy, state);
> + if (ret) {
> + pr_err("BOOST cannot %sable low level code (%d)\n",
> + state ? "en" : "dis", ret);
> + return ret;
> + }
> + }
> +
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +
> + pr_debug("cpufreq BOOST %sabled\n", state ? "en" : "dis");
> +
> + return 0;
> +}
> +
> +/**
> + * cpufreq_boost_notifier - notifier callback for cpufreq policy change.
> + * <at> nb: struct notifier_block * with callback info.
> + * <at> event: value showing cpufreq event for which this function invoked.
> + * <at> data: callback-specific data
> + */
> +static int cpufreq_boost_notifier(struct notifier_block *nb,
> + unsigned long event, void *data)
> +{
> + struct cpufreq_policy *policy = data;
> +
> + if (event == CPUFREQ_INCOMPATIBLE) {
> + if (!policy || !policy->boost)
> + return -ENODEV;
> +
> + if (policy->boost->status == CPUFREQ_BOOST_EN) {
> + pr_info("NOTIFIER BOOST: MAX: %d e:%lu cpu: %d\n",
> + policy->max, event, policy->cpu);
> + cpufreq_boost_trigger_state(policy, 0);
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Notifier for cpufreq policy change */
> +static struct notifier_block cpufreq_boost_notifier_block = {
> + .notifier_call = cpufreq_boost_notifier,
> +};
> +
> +int cpufreq_boost_init(struct cpufreq_policy *policy)
> +{
> + int ret = 0;
> +
> + if (!policy)
> + return -EINVAL;
Heh, policy can't be NULL here.
> + if (!cpufreq_driver->boost) {
> + pr_err("Boost mode not supported on this device\n");
Wow!! You want to screw everybody else's logs with this message.
Its not a crime if you don't have boost mode supported :)
Actually this routine must be called only if cpufreq_driver->boost
is valid.
> + return -ENODEV;
> + }
> +
> + policy->boost = cpufreq_boost = cpufreq_driver->boost;
Why are we copying same pointer to policy->boost? Driver is
passing pointer to a single memory location, just save it globally.
> + /* disable boost for newly created policy - as we e.g. change
> + governor */
> + policy->boost->status = CPUFREQ_BOOST_DIS;
Drivers supporting boost may want boost to be enabled by default,
maybe without any sysfs calls.
> + /* register policy notifier */
> + ret = cpufreq_register_notifier(&cpufreq_boost_notifier_block,
> + CPUFREQ_POLICY_NOTIFIER);
> + if (ret) {
> + pr_err("CPUFREQ BOOST notifier not registered.\n");
> + return ret;
> + }
> + /* add policy to policies list headed at struct cpufreq_boost */
> + list_add_tail(&policy->boost_list, &cpufreq_boost->policies);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_boost_init);
Why do we need to maintain a list of boost here? notifiers? complex :(
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -1954,6 +2106,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> pr_debug("unregistering driver %s\n", driver->name);
>
> subsys_interface_unregister(&cpufreq_interface);
> +
> + if (cpufreq_driver->boost)
> + sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
You haven't removed this from policy. Memory leak.
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index d7a7966..0e95524 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -3,6 +3,8 @@
> *
> * Copyright (C) 2002 - 2003 Dominik Brodowski
> *
> + * Copyright (C) 2013 Lukasz Majewski <[email protected]>
> + *
You shouldn't add it unless you did some major work on this file. You aren't
maintaining this file in 2013.
> +static int cpufreq_frequency_table_skip_boost(struct cpufreq_policy *policy,
> + unsigned int index)
> +{
> + if (index == CPUFREQ_BOOST)
> + if (!policy->boost ||
This shouldn't be true. If index has got CPUFREQ_BOOST, then driver
has to support boost.
> + policy->boost->status == CPUFREQ_BOOST_DIS)
> + return 1;
> +
> + return 0;
> +}
> +
> +unsigned int
> +cpufreq_frequency_table_boost_max(struct cpufreq_frequency_table *freq_table)
> +{
> + int index, boost_freq_max;
> +
> + for (index = 0, boost_freq_max = 0;
> + freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
> + if (freq_table[index].index == CPUFREQ_BOOST) {
> + if (freq_table[index].frequency > boost_freq_max)
> + boost_freq_max = freq_table[index].frequency;
> + }
> +
> + return boost_freq_max;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_boost_max);
why do we need this?
> /*
> * if you use these, you must assure that the frequency table is valid
> * all the time between get_attr and put_attr!
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 037d36a..1294c8c 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -88,6 +88,25 @@ struct cpufreq_real_policy {
> struct cpufreq_governor *governor; /* see below */
> };
>
> +#define CPUFREQ_BOOST_DIS (0)
> +#define CPUFREQ_BOOST_EN (1)
You don't need these.. Just create variable as bool and 0 & 1 would
be fine.
> +struct cpufreq_policy;
> +struct cpufreq_boost {
> + unsigned int max_boost_freq; /* maximum value of
> + * boosted freq */
> + unsigned int max_normal_freq; /* non boost max freq */
> + int status; /* status of boost */
> +
> + /* boost sysfs attributies */
> + struct freq_attr **attr;
> +
> + /* low-level trigger for boost */
> + int (*low_level_boost) (struct cpufreq_policy *policy, int state);
> +
> + struct list_head policies;
> +};
We don't need it. Just add two more fields to cpufreq_driver:
- have_boost_freqs and low_level_boost (maybe a better name.
What's its use?)
> struct cpufreq_policy {
> /* CPUs sharing clock, require sw coordination */
> cpumask_var_t cpus; /* Online CPUs only */
> @@ -113,6 +132,9 @@ struct cpufreq_policy {
>
> struct cpufreq_real_policy user_policy;
>
> + struct cpufreq_boost *boost;
> + struct list_head boost_list;
We don't need both of these.
> struct kobject kobj;
> struct completion kobj_unregister;
> };
> @@ -277,7 +302,6 @@ struct cpufreq_driver {
> int cpufreq_register_driver(struct cpufreq_driver *driver_data);
> int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
>
> -
??
> void cpufreq_notify_transition(struct cpufreq_policy *policy,
> struct cpufreq_freqs *freqs, unsigned int state);
>
> @@ -403,6 +427,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
> #define CPUFREQ_ENTRY_INVALID ~0
> #define CPUFREQ_TABLE_END ~1
>
> +/* Define index for boost frequency */
> +#define CPUFREQ_BOOST ~2
s/CPUFREQ_BOOST/CPUFREQ_BOOST_FREQ
Hi Viresh,
> Hi,
>
> On 6 June 2013 12:37, Lukasz Majewski <[email protected]> wrote:
> > This commit adds support for software based frequency boosting.
> > Exynos4 SoCs (e.g. 4x12) allow setting of frequency above its normal
> > condition limits. This can be done for some short time.
> >
> > Overclocking (boost) support came from cpufreq driver (which is
> > platform dependent). Hence the data structure describing it is
> > defined at its file.
> >
> > To allow support for either SW and HW (Intel) based boosting, the
> > cpufreq core code has been extended to support both solutions.
> >
> > The main boost switch has been put
> > at /sys/devices/system/cpu/cpufreq/boost.
>
> Log requires some better paragraphs but I am not concerned about it
> for now.
>
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> > ---
> > drivers/cpufreq/cpufreq.c | 156
> > ++++++++++++++++++++++++++++++++++++++++++
> > drivers/cpufreq/freq_table.c | 87 ++++++++++++++++++++++-
> > include/linux/cpufreq.h | 35 +++++++++- 3 files changed, 275
> > insertions(+), 3 deletions(-)
>
> My initial view on this patch is: "It is overly engineered and needs
> to get simplified"
>
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index ca74e27..8cf9a92 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -133,6 +133,11 @@ bool have_governor_per_policy(void)
> > return cpufreq_driver->have_governor_per_policy;
> > }
> >
> > +/**
> > + * Global definition of cpufreq_boost structure
> > + */
> > +struct cpufreq_boost *cpufreq_boost;
>
> Probably just a 'static bool' here cpufreq_boost_enabled. Which takes
> care of selection from sysfs.
The pointer to struct cpufreq_boost is needed for further reference
(as it is now done with struct cpufreq_driver pointer - *cpufreq_driver
- defined at cpufreq.c file).
>
> > static struct cpufreq_governor *__find_governor(const char
> > *str_governor) {
> > @@ -761,6 +805,18 @@ static int cpufreq_add_dev_interface(unsigned
> > int cpu, if (cpufreq_set_drv_attr_files(policy,
> > cpufreq_driver->attr)) goto err_out_kobj_put;
> >
> > + if (cpufreq_driver->boost) {
> > + if (sysfs_create_file(cpufreq_global_kobject,
> > + &(global_boost.attr)))
>
> This will report error for systems where we have two policy
> structures. As we are creating something already present.
Good point, thanks.
>
> > + pr_warn("could not register global boost
> > sysfs file\n");
> > + else
> > + pr_debug("registered global boost sysfs
> > file\n");
>
> Please make all your prints to print function name too:
>
> pr_debug("%s: foo\n", __func__, foo);
OK.
>
> > + if (cpufreq_set_drv_attr_files(policy,
> > +
> > cpufreq_driver->boost->attr))
>
> Why is this required? Why do we want platforms to add some files
> in sysfs?
There are two kinds of attributes, which are exported by boost:
1. global boost (/sys/devices/system/cpu/cpufreq/boost)
2. attributes describing cpufreq abilities when boost is available
(/sys/devices/syste/cpu/cpu0/cpufreq/):
- scaling_boost_frequencies - which will show over clocked
frequencies
- the scaling_available_frequencies will also display boosted
frequency (when boost enabled)
Information from 2. is cpufreq_driver dependent. And that information
shouldn't been displayed when boost is not available
>
> > /*********************************************************************
> > + *
> > BOOST *
> > +
> > *********************************************************************/
> > +int cpufreq_boost_trigger_state(struct cpufreq_policy *policy, int
> > state) +{
> > + struct cpufreq_boost *boost;
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (!policy || !policy->boost
> > || !policy->boost->low_level_boost)
> > + return -ENODEV;
> > +
> > + boost = policy->boost;
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > +
> > + if (boost->status != state) {
> > + policy->boost->status = state;
> > + ret = boost->low_level_boost(policy, state);
> > + if (ret) {
> > + pr_err("BOOST cannot %sable low level code
> > (%d)\n",
> > + state ? "en" : "dis", ret);
> > + return ret;
> > + }
> > + }
> > +
> > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > +
> > + pr_debug("cpufreq BOOST %sabled\n", state ? "en" : "dis");
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * cpufreq_boost_notifier - notifier callback for cpufreq policy
> > change.
> > + * <at> nb: struct notifier_block * with callback info.
> > + * <at> event: value showing cpufreq event for which this
> > function invoked.
> > + * <at> data: callback-specific data
> > + */
> > +static int cpufreq_boost_notifier(struct notifier_block *nb,
> > + unsigned long event, void *data)
> > +{
> > + struct cpufreq_policy *policy = data;
> > +
> > + if (event == CPUFREQ_INCOMPATIBLE) {
> > + if (!policy || !policy->boost)
> > + return -ENODEV;
> > +
> > + if (policy->boost->status == CPUFREQ_BOOST_EN) {
> > + pr_info("NOTIFIER BOOST: MAX: %d e:%lu cpu:
> > %d\n",
> > + policy->max, event, policy->cpu);
> > + cpufreq_boost_trigger_state(policy, 0);
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/* Notifier for cpufreq policy change */
> > +static struct notifier_block cpufreq_boost_notifier_block = {
> > + .notifier_call = cpufreq_boost_notifier,
> > +};
> > +
> > +int cpufreq_boost_init(struct cpufreq_policy *policy)
> > +{
> > + int ret = 0;
> > +
> > + if (!policy)
> > + return -EINVAL;
>
> Heh, policy can't be NULL here.
Extra precautions :-). I will remove it.
>
> > + if (!cpufreq_driver->boost) {
> > + pr_err("Boost mode not supported on this device\n");
>
> Wow!! You want to screw everybody else's logs with this message.
> Its not a crime if you don't have boost mode supported :)
Hmm, I've exaggerated a bit here.... :)
>
> Actually this routine must be called only if cpufreq_driver->boost
> is valid.
>
> > + return -ENODEV;
> > + }
> > +
> > + policy->boost = cpufreq_boost = cpufreq_driver->boost;
>
> Why are we copying same pointer to policy->boost? Driver is
> passing pointer to a single memory location, just save it globally.
This needs some explanation.
The sysfs entry presented at [1] doesn't bring any useful information
to reuse (like *policy). For this reason the global cpufreq_boost
pointer is needed.
However to efficiently manage the boost, it is necessary to keep per
policy pointer to the only struct cpufreq_boost instance (defined at
cpufreq_driver code).
>
> > + /* disable boost for newly created policy - as we e.g.
> > change
> > + governor */
> > + policy->boost->status = CPUFREQ_BOOST_DIS;
>
> Drivers supporting boost may want boost to be enabled by default,
> maybe without any sysfs calls.
This can be done by setting the struct cpufreq_boost status field to
CPUFREQ_BOOST_EN at cpufreq driver code (when boost structure is
defined)
>
> > + /* register policy notifier */
> > + ret =
> > cpufreq_register_notifier(&cpufreq_boost_notifier_block,
> > + CPUFREQ_POLICY_NOTIFIER);
> > + if (ret) {
> > + pr_err("CPUFREQ BOOST notifier not registered.\n");
> > + return ret;
> > + }
> > + /* add policy to policies list headed at struct
> > cpufreq_boost */
> > + list_add_tail(&policy->boost_list,
> > &cpufreq_boost->policies); +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_boost_init);
>
> Why do we need to maintain a list of boost here? notifiers? complex :(
Notifier is needed to disable boost when policy is changed (for
example when we change from ondemand/lab to performance governor).
I wanted to avoid the situation when boost stays enabled across
different governors.
The list of in system available policies is defined to allow boost
enable/disable for all policies available (by changing for example
policy->max field).
If we decide, that we will support only one policy (as it is now at
e.g. Exynos), the list is unnecessary here.
>
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -1954,6 +2106,10 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> > subsys_interface_unregister(&cpufreq_interface);
> > +
> > + if (cpufreq_driver->boost)
> > + sysfs_remove_file(cpufreq_global_kobject,
> > &(global_boost.attr));
>
> You haven't removed this from policy. Memory leak.
Yes, you are right.
>
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > diff --git a/drivers/cpufreq/freq_table.c
> > b/drivers/cpufreq/freq_table.c index d7a7966..0e95524 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -3,6 +3,8 @@
> > *
> > * Copyright (C) 2002 - 2003 Dominik Brodowski
> > *
> > + * Copyright (C) 2013 Lukasz Majewski <[email protected]>
> > + *
>
> You shouldn't add it unless you did some major work on this file. You
> aren't maintaining this file in 2013.
OK, I will remove the entry.
>
> > +static int cpufreq_frequency_table_skip_boost(struct
> > cpufreq_policy *policy,
> > + unsigned int index)
> > +{
> > + if (index == CPUFREQ_BOOST)
> > + if (!policy->boost ||
>
> This shouldn't be true. If index has got CPUFREQ_BOOST, then driver
> has to support boost.
Correct me if I'm wrong here, but in my understanding the boost shall be
only supported when both CPUFREQ_BOOST index is defined in a freq_table
and boost.state = CPUFREQ_BOOST_EN is set.
Setting of CPUFREQ_BOOST shouldn't by default allow to use over
clocking frequency.
>
> > + policy->boost->status == CPUFREQ_BOOST_DIS)
> > + return 1;
> > +
> > + return 0;
> > +}
> > +
> > +unsigned int
> > +cpufreq_frequency_table_boost_max(struct cpufreq_frequency_table
> > *freq_table) +{
> > + int index, boost_freq_max;
> > +
> > + for (index = 0, boost_freq_max = 0;
> > + freq_table[index].frequency != CPUFREQ_TABLE_END;
> > index++)
> > + if (freq_table[index].index == CPUFREQ_BOOST) {
> > + if (freq_table[index].frequency >
> > boost_freq_max)
> > + boost_freq_max =
> > freq_table[index].frequency;
> > + }
> > +
> > + return boost_freq_max;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_boost_max);
>
> why do we need this?
To evaluate the maximal boost frequency from the frequency table. It is
then used as a delimiter (when LAB cooperates with thermal framework).
>
> > /*
> > * if you use these, you must assure that the frequency table is
> > valid
> > * all the time between get_attr and put_attr!
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index 037d36a..1294c8c 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -88,6 +88,25 @@ struct cpufreq_real_policy {
> > struct cpufreq_governor *governor; /* see below */
> > };
> >
> > +#define CPUFREQ_BOOST_DIS (0)
> > +#define CPUFREQ_BOOST_EN (1)
>
> You don't need these.. Just create variable as bool and 0 & 1 would
> be fine.
Yes, this seems to be a clearer solution.
>
> > +struct cpufreq_policy;
> > +struct cpufreq_boost {
> > + unsigned int max_boost_freq; /* maximum value of
> > + * boosted freq */
> > + unsigned int max_normal_freq; /* non boost max
> > freq */
> > + int status; /* status of boost */
> > +
> > + /* boost sysfs attributies */
> > + struct freq_attr **attr;
> > +
> > + /* low-level trigger for boost */
> > + int (*low_level_boost) (struct cpufreq_policy *policy, int
> > state); +
> > + struct list_head policies;
> > +};
>
> We don't need it. Just add two more fields to cpufreq_driver:
> - have_boost_freqs and low_level_boost (maybe a better name.
> What's its use?)
The separate struct cpufreq_boost was created to explicitly separate
boost fields from cpufreq_driver structure.
If in your opinion this structure is redundant, I can remove it and
extend cpufreq_driver structure.
>
> > struct cpufreq_policy {
> > /* CPUs sharing clock, require sw coordination */
> > cpumask_var_t cpus; /* Online CPUs only */
> > @@ -113,6 +132,9 @@ struct cpufreq_policy {
> >
> > struct cpufreq_real_policy user_policy;
> >
> > + struct cpufreq_boost *boost;
> > + struct list_head boost_list;
>
> We don't need both of these.
*boost pointer is necessary when one wants to enable/disable boost from
e.g governor code (which operates mostly on struct cpufreq_policy
*policy pointers).
The boost_list is necessary to connect policies in a list.
>
> > struct kobject kobj;
> > struct completion kobj_unregister;
> > };
>
> > @@ -277,7 +302,6 @@ struct cpufreq_driver {
> > int cpufreq_register_driver(struct cpufreq_driver *driver_data);
> > int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
> >
> > -
>
> ??
>
> > void cpufreq_notify_transition(struct cpufreq_policy *policy,
> > struct cpufreq_freqs *freqs, unsigned int state);
> >
> > @@ -403,6 +427,9 @@ extern struct cpufreq_governor
> > cpufreq_gov_conservative; #define CPUFREQ_ENTRY_INVALID ~0
> > #define CPUFREQ_TABLE_END ~1
> >
> > +/* Define index for boost frequency */
> > +#define CPUFREQ_BOOST ~2
>
> s/CPUFREQ_BOOST/CPUFREQ_BOOST_FREQ
Ok, will be changed to something more descriptive.
Thanks for thorough review :-)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
> +config CPU_FREQ_BOOST
> + bool "CPU frequency boost support"
> + help
> + Switch to enable support for frequency boost
> +
> + If in doubt, say N.
> +
This help text is devoid of any useful information.
On what platforms ? What's the upside/downside ? Why is it an option ?
Dave
Hi Dave,
> On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
>
> > +config CPU_FREQ_BOOST
> > + bool "CPU frequency boost support"
> > + help
> > + Switch to enable support for frequency boost
> > +
> > + If in doubt, say N.
> > +
>
> This help text is devoid of any useful information.
>
> On what platforms ? What's the upside/downside ? Why is it an option ?
I shall be more verbose here.
The boost option is supposed to provide one solution to control
software based (like is is done with Samsung Exynos4 SoC) and hardware
based (like Intel's Turbo Boost feature) boost.
Support for Intel's boost is already in mainline. Therefore I aimed to
extend cpufreq to also manage software based solutions (e.g. Exynos).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thu, Jun 06, 2013 at 05:14:31PM +0200, Lukasz Majewski wrote:
> Hi Dave,
>
> > On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
> >
> > > +config CPU_FREQ_BOOST
> > > + bool "CPU frequency boost support"
> > > + help
> > > + Switch to enable support for frequency boost
> > > +
> > > + If in doubt, say N.
> > > +
> >
> > This help text is devoid of any useful information.
> >
> > On what platforms ? What's the upside/downside ? Why is it an option ?
>
> I shall be more verbose here.
>
> The boost option is supposed to provide one solution to control
> software based (like is is done with Samsung Exynos4 SoC) and hardware
> based (like Intel's Turbo Boost feature) boost.
>
> Support for Intel's boost is already in mainline. Therefore I aimed to
> extend cpufreq to also manage software based solutions (e.g. Exynos).
Given CPUFREQ is available on more platforms than X86/ARM, this option
could also use a depends.
Dave
On 6 June 2013 17:19, Lukasz Majewski <[email protected]> wrote:
>> On 6 June 2013 12:37, Lukasz Majewski <[email protected]> wrote:
>> > cpufreq_driver->boost->attr))
>>
>> Why is this required? Why do we want platforms to add some files
>> in sysfs?
>
> There are two kinds of attributes, which are exported by boost:
>
> 1. global boost (/sys/devices/system/cpu/cpufreq/boost)
>
> 2. attributes describing cpufreq abilities when boost is available
> (/sys/devices/syste/cpu/cpu0/cpufreq/):
> - scaling_boost_frequencies - which will show over clocked
> frequencies
> - the scaling_available_frequencies will also display boosted
> frequency (when boost enabled)
>
> Information from 2. is cpufreq_driver dependent. And that information
> shouldn't been displayed when boost is not available
This is not how I wanted this to be coded. Lets keep things simple:
- Implement it in the way cpufreq_freq_attr_scaling_available_freqs
is implemented. And then drivers which need to see boost freqs
can add it in their attr.
>> > + policy->boost = cpufreq_boost = cpufreq_driver->boost;
>>
>> Why are we copying same pointer to policy->boost? Driver is
>> passing pointer to a single memory location, just save it globally.
>
> This needs some explanation.
>
> The sysfs entry presented at [1] doesn't bring any useful information
> to reuse (like *policy). For this reason the global cpufreq_boost
> pointer is needed.
>
> However to efficiently manage the boost, it is necessary to keep per
> policy pointer to the only struct cpufreq_boost instance (defined at
> cpufreq_driver code).
No we don't need to screw struct cpufreq_policy with it.
Just need two variables here:
- cpufreq_driver->boost: If driver supports boost or not.
- If above is true then a global bool variable that will say boost is
enabled from sysfs or not.
>> > + /* disable boost for newly created policy - as we e.g.
>> > change
>> > + governor */
>> > + policy->boost->status = CPUFREQ_BOOST_DIS;
>>
>> Drivers supporting boost may want boost to be enabled by default,
>> maybe without any sysfs calls.
>
> This can be done by setting the struct cpufreq_boost status field to
> CPUFREQ_BOOST_EN at cpufreq driver code (when boost structure is
> defined)
This really isn't driver dependent.. But user dependent. Maybe lets
keep it disabled and people can enable it from sysfs.
>> Why do we need to maintain a list of boost here? notifiers? complex :(
>
> Notifier is needed to disable boost when policy is changed (for
> example when we change from ondemand/lab to performance governor).
>
> I wanted to avoid the situation when boost stays enabled across
> different governors.
>
> The list of in system available policies is defined to allow boost
> enable/disable for all policies available (by changing for example
> policy->max field).
>
> If we decide, that we will support only one policy (as it is now at
> e.g. Exynos), the list is unnecessary here.
What we discussed last in your earlier patchset was:
- Keep boost feature separate from governors.
- If it is enabled, then any governor can use it (if they want).
- Lets not disable it if governor is changed. user must do it explicitly.
>> > +static int cpufreq_frequency_table_skip_boost(struct
>> > cpufreq_policy *policy,
>> > + unsigned int index)
>> > +{
>> > + if (index == CPUFREQ_BOOST)
>> > + if (!policy->boost ||
>>
>> This shouldn't be true. If index has got CPUFREQ_BOOST, then driver
>> has to support boost.
>
> Correct me if I'm wrong here, but in my understanding the boost shall be
> only supported when both CPUFREQ_BOOST index is defined in a freq_table
> and boost.state = CPUFREQ_BOOST_EN is set.
>
> Setting of CPUFREQ_BOOST shouldn't by default allow to use over
> clocking frequency.
For cpufreq core boost is enabled as soon as cpufreq_driver->boost is
true. We can have additional checks to see if there is atleast one
boost frequency but can skip this too.
>> why do we need this?
>
> To evaluate the maximal boost frequency from the frequency table. It is
> then used as a delimiter (when LAB cooperates with thermal framework).
Introduce this with LAB then.. Lets keep it as simple as possible for now.
One step at a time.
>> > +struct cpufreq_boost {
>> > + unsigned int max_boost_freq; /* maximum value of
>> > + * boosted freq */
>> > + unsigned int max_normal_freq; /* non boost max
>> > freq */
>> > + int status; /* status of boost */
>> > +
>> > + /* boost sysfs attributies */
>> > + struct freq_attr **attr;
>> > +
>> > + /* low-level trigger for boost */
>> > + int (*low_level_boost) (struct cpufreq_policy *policy, int
>> > state); +
>> > + struct list_head policies;
>> > +};
>>
>> We don't need it. Just add two more fields to cpufreq_driver:
>> - have_boost_freqs and low_level_boost (maybe a better name.
>> What's its use?)
>
> The separate struct cpufreq_boost was created to explicitly separate
> boost fields from cpufreq_driver structure.
>
> If in your opinion this structure is redundant, I can remove it and
> extend cpufreq_driver structure.
I am not against a structure (as putting related stuff in a struct is always
better), but against so many fields in it to make things complicated.
I will only keep have_boost_freqs and low_level_boost. Remove
everything else.
> *boost pointer is necessary when one wants to enable/disable boost from
> e.g governor code (which operates mostly on struct cpufreq_policy
> *policy pointers).
We don't need to do this. boost can only be disabled from userspace by
user. No intervention from governor.
On 6 June 2013 20:51, Dave Jones <[email protected]> wrote:
> Given CPUFREQ is available on more platforms than X86/ARM, this option
> could also use a depends.
It should be disabled by default, so please add default n.
But we don't need a depends here as everybody is open to use
it. Its a core feature.
On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
> Enable/disable support for BOOST. New flag - CPU_FREQ_BOOST has been
> defined for that.
What's the reason for this? Why would you want to not compile-in the
boosting code?
Also, at least on x86, even with this feature disabled, the CPU will
boost by default unless you fiddle with it through the MSRs as root.
--
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--
Hi Viresh,
> On 6 June 2013 17:19, Lukasz Majewski <[email protected]> wrote:
> >> On 6 June 2013 12:37, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > cpufreq_driver->boost->attr))
> >>
> >> Why is this required? Why do we want platforms to add some files
> >> in sysfs?
> >
> > There are two kinds of attributes, which are exported by boost:
> >
> > 1. global boost (/sys/devices/system/cpu/cpufreq/boost)
> >
> > 2. attributes describing cpufreq abilities when boost is available
> > (/sys/devices/syste/cpu/cpu0/cpufreq/):
> > - scaling_boost_frequencies - which will show over clocked
> > frequencies
> > - the scaling_available_frequencies will also display
> > boosted frequency (when boost enabled)
> >
> > Information from 2. is cpufreq_driver dependent. And that
> > information shouldn't been displayed when boost is not available
>
> This is not how I wanted this to be coded. Lets keep things simple:
> - Implement it in the way cpufreq_freq_attr_scaling_available_freqs
> is implemented. And then drivers which need to see boost freqs
> can add it in their attr.
>
> >> > + policy->boost = cpufreq_boost = cpufreq_driver->boost;
> >>
> >> Why are we copying same pointer to policy->boost? Driver is
> >> passing pointer to a single memory location, just save it globally.
> >
> > This needs some explanation.
> >
> > The sysfs entry presented at [1] doesn't bring any useful
> > information to reuse (like *policy). For this reason the global
> > cpufreq_boost pointer is needed.
> >
> > However to efficiently manage the boost, it is necessary to keep per
> > policy pointer to the only struct cpufreq_boost instance (defined at
> > cpufreq_driver code).
>
> No we don't need to screw struct cpufreq_policy with it.
> Just need two variables here:
> - cpufreq_driver->boost: If driver supports boost or not.
> - If above is true then a global bool variable that will say boost is
> enabled from sysfs or not.
>
> >> > + /* disable boost for newly created policy - as we e.g.
> >> > change
> >> > + governor */
> >> > + policy->boost->status = CPUFREQ_BOOST_DIS;
> >>
> >> Drivers supporting boost may want boost to be enabled by default,
> >> maybe without any sysfs calls.
> >
> > This can be done by setting the struct cpufreq_boost status field to
> > CPUFREQ_BOOST_EN at cpufreq driver code (when boost structure is
> > defined)
>
> This really isn't driver dependent.. But user dependent. Maybe lets
> keep it disabled and people can enable it from sysfs.
>
> >> Why do we need to maintain a list of boost here? notifiers?
> >> complex :(
> >
> > Notifier is needed to disable boost when policy is changed (for
> > example when we change from ondemand/lab to performance governor).
> >
> > I wanted to avoid the situation when boost stays enabled across
> > different governors.
> >
> > The list of in system available policies is defined to allow boost
> > enable/disable for all policies available (by changing for example
> > policy->max field).
> >
> > If we decide, that we will support only one policy (as it is now at
> > e.g. Exynos), the list is unnecessary here.
>
> What we discussed last in your earlier patchset was:
> - Keep boost feature separate from governors.
> - If it is enabled, then any governor can use it (if they want).
> - Lets not disable it if governor is changed. user must do it
> explicitly.
>
> >> > +static int cpufreq_frequency_table_skip_boost(struct
> >> > cpufreq_policy *policy,
> >> > + unsigned int index)
> >> > +{
> >> > + if (index == CPUFREQ_BOOST)
> >> > + if (!policy->boost ||
> >>
> >> This shouldn't be true. If index has got CPUFREQ_BOOST, then driver
> >> has to support boost.
> >
> > Correct me if I'm wrong here, but in my understanding the boost
> > shall be only supported when both CPUFREQ_BOOST index is defined in
> > a freq_table and boost.state = CPUFREQ_BOOST_EN is set.
> >
> > Setting of CPUFREQ_BOOST shouldn't by default allow to use over
> > clocking frequency.
>
> For cpufreq core boost is enabled as soon as cpufreq_driver->boost is
> true. We can have additional checks to see if there is atleast one
> boost frequency but can skip this too.
>
> >> why do we need this?
> >
> > To evaluate the maximal boost frequency from the frequency table.
> > It is then used as a delimiter (when LAB cooperates with thermal
> > framework).
>
> Introduce this with LAB then.. Lets keep it as simple as possible for
> now. One step at a time.
>
> >> > +struct cpufreq_boost {
> >> > + unsigned int max_boost_freq; /* maximum value
> >> > of
> >> > + * boosted freq
> >> > */
> >> > + unsigned int max_normal_freq; /* non boost max
> >> > freq */
> >> > + int status; /* status of boost */
> >> > +
> >> > + /* boost sysfs attributies */
> >> > + struct freq_attr **attr;
> >> > +
> >> > + /* low-level trigger for boost */
> >> > + int (*low_level_boost) (struct cpufreq_policy *policy,
> >> > int state); +
> >> > + struct list_head policies;
> >> > +};
> >>
> >> We don't need it. Just add two more fields to cpufreq_driver:
> >> - have_boost_freqs and low_level_boost (maybe a better name.
> >> What's its use?)
> >
> > The separate struct cpufreq_boost was created to explicitly separate
> > boost fields from cpufreq_driver structure.
> >
> > If in your opinion this structure is redundant, I can remove it and
> > extend cpufreq_driver structure.
>
> I am not against a structure (as putting related stuff in a struct is
> always better), but against so many fields in it to make things
> complicated.
>
> I will only keep have_boost_freqs and low_level_boost. Remove
> everything else.
I would prefer to have following fields in the cpufreq_boost structure:
struct cpufreq_boost {
unsigned int max_boost_freq; /*boost max freq*/
unsigned int max_normal_freq; /*max normal freq
int (*low_level_boost) (int state);
bool boost_en; /* indicate if boost is enabled */
}
The max_{boost|normal}_freq fields will be filed at
ret = cpufreq_driver->init(policy);
Thanks to them I will avoid calling many times routine, which extracts
from freq_table maximal boost and normal frequencies.
I could define those variables in the exynos-cpufreq.c driver, but I
think, that they are more suitable to be embedded at cpufreq_boost
structure.
>
> > *boost pointer is necessary when one wants to enable/disable boost
> > from e.g governor code (which operates mostly on struct
> > cpufreq_policy *policy pointers).
>
> We don't need to do this. boost can only be disabled from userspace by
> user. No intervention from governor.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Hi Lukasz,
On 7 June 2013 18:57, Lukasz Majewski <[email protected]> wrote:
I hope you agreed to all the other comments I gave as I don't see an
explicit reply below each of these. I have seen people missing these
in past, so what would be better to do is:
- either reply below each one of them and say yes or no..
- Or write once below many comments and say: All above comments
are accepted.
So, that Reviewer is assured that you haven't missed anything.
> I would prefer to have following fields in the cpufreq_boost structure:
> struct cpufreq_boost {
> unsigned int max_boost_freq; /*boost max freq*/
> unsigned int max_normal_freq; /*max normal freq
> int (*low_level_boost) (int state);
> bool boost_en; /* indicate if boost is enabled */
> }
>
> The max_{boost|normal}_freq fields will be filed at
> ret = cpufreq_driver->init(policy);
>
> Thanks to them I will avoid calling many times routine, which extracts
> from freq_table maximal boost and normal frequencies.
>
> I could define those variables in the exynos-cpufreq.c driver, but I
> think, that they are more suitable to be embedded at cpufreq_boost
> structure.
I understand that you need these variables (I will still look how you are
using them in next version). But they are per policy and driver isn't
responsible for maintaining them. If they are required then cpufreq
core must find them out and keep in struct cpufreq_policy (as they
are policy dependent)..
So, remove this structure from cpufreq_driver and embed variables
directly.
Hi Viresh,
> Hi Lukasz,
>
> On 7 June 2013 18:57, Lukasz Majewski <[email protected]> wrote:
>
> I hope you agreed to all the other comments I gave as I don't see an
> explicit reply below each of these. I have seen people missing these
> in past, so what would be better to do is:
> - either reply below each one of them and say yes or no..
> - Or write once below many comments and say: All above comments
> are accepted.
>
> So, that Reviewer is assured that you haven't missed anything.
>
Thanks for reminding :-).
I've read through all the comments. I'm redesigning now the driver to
remove redundant code.
> > I would prefer to have following fields in the cpufreq_boost
> > structure: struct cpufreq_boost {
> > unsigned int max_boost_freq; /*boost max freq*/
> > unsigned int max_normal_freq; /*max normal freq
> > int (*low_level_boost) (int state);
> > bool boost_en; /* indicate if boost is enabled */
> > }
> >
> > The max_{boost|normal}_freq fields will be filed at
> > ret = cpufreq_driver->init(policy);
> >
> > Thanks to them I will avoid calling many times routine, which
> > extracts from freq_table maximal boost and normal frequencies.
> >
> > I could define those variables in the exynos-cpufreq.c driver, but I
> > think, that they are more suitable to be embedded at cpufreq_boost
> > structure.
>
> I understand that you need these variables (I will still look how you
> are using them in next version). But they are per policy and driver
> isn't responsible for maintaining them. If they are required then
> cpufreq core must find them out and keep in struct cpufreq_policy (as
> they are policy dependent)..
>
> So, remove this structure from cpufreq_driver and embed variables
> directly.
After refactoring the code. I admit, that we shall embed the struct
cpu_boost fields directly to the coufreq_driver. There is no point to
create structure with 2 fields.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Hi Viresh,
> On 6 June 2013 17:19, Lukasz Majewski <[email protected]> wrote:
> >> On 6 June 2013 12:37, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > cpufreq_driver->boost->attr))
> >>
> >> Why is this required? Why do we want platforms to add some files
> >> in sysfs?
> >
> > There are two kinds of attributes, which are exported by boost:
> >
> > 1. global boost (/sys/devices/system/cpu/cpufreq/boost)
> >
> > 2. attributes describing cpufreq abilities when boost is available
> > (/sys/devices/syste/cpu/cpu0/cpufreq/):
> > - scaling_boost_frequencies - which will show over clocked
> > frequencies
> > - the scaling_available_frequencies will also display
> > boosted frequency (when boost enabled)
> >
> > Information from 2. is cpufreq_driver dependent. And that
> > information shouldn't been displayed when boost is not available
>
> This is not how I wanted this to be coded. Lets keep things simple:
> - Implement it in the way cpufreq_freq_attr_scaling_available_freqs
> is implemented. And then drivers which need to see boost freqs
> can add it in their attr.
I've added scaling_boost_frequencies to cpufreq_driver attr.
However, I would keep the boost attributes definition in the freq_table
file (as I've proposed in my patch).
>
> >> > + policy->boost = cpufreq_boost = cpufreq_driver->boost;
> >>
> >> Why are we copying same pointer to policy->boost? Driver is
> >> passing pointer to a single memory location, just save it globally.
> >
> > This needs some explanation.
> >
> > The sysfs entry presented at [1] doesn't bring any useful
> > information to reuse (like *policy). For this reason the global
> > cpufreq_boost pointer is needed.
> >
> > However to efficiently manage the boost, it is necessary to keep per
> > policy pointer to the only struct cpufreq_boost instance (defined at
> > cpufreq_driver code).
>
> No we don't need to screw struct cpufreq_policy with it.
> Just need two variables here:
> - cpufreq_driver->boost: If driver supports boost or not.
This will be done as above.
> - If above is true then a global bool variable that will say boost is
> enabled from sysfs or not.
One global flag will be defined at cpufreq.c to indicate if global
boost sysfs attr has been created.
>
> >> > + /* disable boost for newly created policy - as we e.g.
> >> > change
> >> > + governor */
> >> > + policy->boost->status = CPUFREQ_BOOST_DIS;
> >>
> >> Drivers supporting boost may want boost to be enabled by default,
> >> maybe without any sysfs calls.
> >
> > This can be done by setting the struct cpufreq_boost status field to
> > CPUFREQ_BOOST_EN at cpufreq driver code (when boost structure is
> > defined)
>
> This really isn't driver dependent.. But user dependent. Maybe lets
> keep it disabled and people can enable it from sysfs.
The cpufreq_driver struct will have boost_en field. This will allow
keep boost state (it is similar to global boost_enable at
acpi-cpufreq.c).
>
> >> Why do we need to maintain a list of boost here? notifiers?
> >> complex :(
> >
> > Notifier is needed to disable boost when policy is changed (for
> > example when we change from ondemand/lab to performance governor).
> >
> > I wanted to avoid the situation when boost stays enabled across
> > different governors.
> >
> > The list of in system available policies is defined to allow boost
> > enable/disable for all policies available (by changing for example
> > policy->max field).
> >
> > If we decide, that we will support only one policy (as it is now at
> > e.g. Exynos), the list is unnecessary here.
>
> What we discussed last in your earlier patchset was:
> - Keep boost feature separate from governors.
Ok.
> - If it is enabled, then any governor can use it (if they want).
Ok, lets do it in this way
> - Lets not disable it if governor is changed. user must do it
> explicitly.
Ok, agree (notifier removed).
>
> >> > +static int cpufreq_frequency_table_skip_boost(struct
> >> > cpufreq_policy *policy,
> >> > + unsigned int index)
> >> > +{
> >> > + if (index == CPUFREQ_BOOST)
> >> > + if (!policy->boost ||
> >>
> >> This shouldn't be true. If index has got CPUFREQ_BOOST, then driver
> >> has to support boost.
> >
> > Correct me if I'm wrong here, but in my understanding the boost
> > shall be only supported when both CPUFREQ_BOOST index is defined in
> > a freq_table and boost.state = CPUFREQ_BOOST_EN is set.
> >
> > Setting of CPUFREQ_BOOST shouldn't by default allow to use over
> > clocking frequency.
>
> For cpufreq core boost is enabled as soon as cpufreq_driver->boost is
> true. We can have additional checks to see if there is atleast one
> boost frequency but can skip this too.
Checks are needed to read max_normal frequency and max boost frequency
from frequency table.
In exynos cpufreq_driver->init() I will disable boost.
>
> >> why do we need this?
> >
> > To evaluate the maximal boost frequency from the frequency table.
> > It is then used as a delimiter (when LAB cooperates with thermal
> > framework).
>
> Introduce this with LAB then.. Lets keep it as simple as possible for
> now. One step at a time.
Sorry, I have LAB in back of my head. For now I'm forgetting about
it :-) [*]
>
> >> > +struct cpufreq_boost {
> >> > + unsigned int max_boost_freq; /* maximum value
> >> > of
> >> > + * boosted freq
> >> > */
> >> > + unsigned int max_normal_freq; /* non boost max
> >> > freq */
> >> > + int status; /* status of boost */
> >> > +
> >> > + /* boost sysfs attributies */
> >> > + struct freq_attr **attr;
> >> > +
> >> > + /* low-level trigger for boost */
> >> > + int (*low_level_boost) (struct cpufreq_policy *policy,
> >> > int state); +
> >> > + struct list_head policies;
> >> > +};
> >>
> >> We don't need it. Just add two more fields to cpufreq_driver:
> >> - have_boost_freqs and low_level_boost (maybe a better name.
> >> What's its use?)
> >
> > The separate struct cpufreq_boost was created to explicitly separate
> > boost fields from cpufreq_driver structure.
> >
> > If in your opinion this structure is redundant, I can remove it and
> > extend cpufreq_driver structure.
>
> I am not against a structure (as putting related stuff in a struct is
> always better), but against so many fields in it to make things
> complicated.
>
> I will only keep have_boost_freqs and low_level_boost. Remove
> everything else.
As I've written at other mail. This struct will have only two fields,
so I will embed those fields at cpufreq_driver.
>
> > *boost pointer is necessary when one wants to enable/disable boost
> > from e.g governor code (which operates mostly on struct
> > cpufreq_policy *policy pointers).
>
> We don't need to do this. boost can only be disabled from userspace by
> user. No intervention from governor.
Let's got for that option (as I've promissed at [*] :-) ).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 7 June 2013 20:04, Lukasz Majewski <[email protected]> wrote:
> After refactoring the code. I admit, that we shall embed the struct
> cpu_boost fields directly to the coufreq_driver. There is no point to
> create structure with 2 fields.
Great!! I will wait for your next version.
Hi,
> On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
> > Enable/disable support for BOOST. New flag - CPU_FREQ_BOOST has been
> > defined for that.
>
> What's the reason for this? Why would you want to not compile-in the
> boosting code?
I think that this flag could be removed and the "boost" could be
compiled-in permanently.
Viresh, what is your opinion?
>
> Also, at least on x86, even with this feature disabled, the CPU will
> boost by default unless you fiddle with it through the MSRs as root.
>
So this is a good argument for removing this flag from Kconfig.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 10 June 2013 18:50, Lukasz Majewski <[email protected]> wrote:
> Hi,
>
>> On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
>> > Enable/disable support for BOOST. New flag - CPU_FREQ_BOOST has been
>> > defined for that.
>>
>> What's the reason for this? Why would you want to not compile-in the
>> boosting code?
>
> I think that this flag could be removed and the "boost" could be
> compiled-in permanently.
>
> Viresh, what is your opinion?
Yes, Borislav is correct. I haven't actually reviewed these last patches as
I saw lots of issues with first one :)
Hi Viresh,
> On 10 June 2013 18:50, Lukasz Majewski <[email protected]> wrote:
> > Hi,
> >
> >> On Thu, Jun 06, 2013 at 09:07:52AM +0200, Lukasz Majewski wrote:
> >> > Enable/disable support for BOOST. New flag - CPU_FREQ_BOOST has
> >> > been defined for that.
> >>
> >> What's the reason for this? Why would you want to not compile-in
> >> the boosting code?
> >
> > I think that this flag could be removed and the "boost" could be
> > compiled-in permanently.
> >
> > Viresh, what is your opinion?
>
> Yes, Borislav is correct. I haven't actually reviewed these last
> patches as I saw lots of issues with first one :)
Ok, thanks :-)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally and disabled by default
The cpufreq_driver is responsibile for providing low_level_boost callback
- struct cpufreq_driver has been extended with boost related fields
- Boost sysfs attributies are seen only when cpufreq driver supports them.
They will not show up until either cpufreq_driver defines low_level_boost
callback or device tree's cpufreq "boost_mode" attribute is defined.
- No special spin_lock for Boost was created. The one from cpufreq_driver
was reused.
- Low level boost trigger function (*low_level_boost function callback) is
necessary to "glue" together acpi-cpufreq boost with software based one.
Tested at: HW:
Exynos 4412 3.10 linux
Exynos 4210 3.10 linux
Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem) test
needed
Two patches were abandoned (comparing to v1):
[PATCH 1/5] cpufreq: Define cpufreq_set_drv_attr_files() to add per CPU sysfs attributes
[PATCH 5/5] cpufreq:boost:Kconfig: Enable boost support at Kconfig
For detailed changelog please look into relevant patches
Lukasz Majewski (3):
cpufreq:boost: CPU frequency boost code unification for software and
hardware solutions
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
drivers/cpufreq/acpi-cpufreq.c | 72 ++++++++++++++------------------------
drivers/cpufreq/cpufreq.c | 69 ++++++++++++++++++++++++++++++++++++
drivers/cpufreq/exynos-cpufreq.c | 49 ++++++++++++++++++++++++--
drivers/cpufreq/freq_table.c | 57 ++++++++++++++++++++++++++++--
include/linux/cpufreq.h | 12 +++++++
5 files changed, 209 insertions(+), 50 deletions(-)
--
1.7.10.4
This commit adds support for software based frequency boosting.
Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
its normal condition limits. Such a change shall be only done for a short
time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) over clocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code.
By default boost is disabled. One global attribute is available at:
/sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with proper call to
sysfs.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
---
drivers/cpufreq/cpufreq.c | 69 ++++++++++++++++++++++++++++++++++++++++++
drivers/cpufreq/freq_table.c | 57 ++++++++++++++++++++++++++++++++--
include/linux/cpufreq.h | 12 ++++++++
3 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1b8a48e..98ba5f1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -40,6 +40,7 @@
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver;
+static bool cpufreq_boost_sysfs_defined;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -315,6 +316,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost_status(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_en);
+}
+
+static ssize_t store_boost_status(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %sable boost!\n", __func__,
+ enable ? "en" : "dis");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static struct global_attr global_boost = __ATTR(boost, 0644,
+ show_boost_status,
+ store_boost_status);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -754,6 +782,17 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
goto err_out_kobj_put;
drv_attr++;
}
+ if (cpufreq_driver->low_level_boost && !cpufreq_boost_sysfs_defined) {
+ ret = sysfs_create_file(cpufreq_global_kobject,
+ &(global_boost.attr));
+ if (ret) {
+ pr_err("%s: cannot register global boost sysfs file\n",
+ __func__);
+ goto err_out_kobj_put;
+ }
+ cpufreq_boost_sysfs_defined = 1;
+ }
+
if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (ret)
@@ -1853,6 +1892,30 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+int cpufreq_boost_trigger_state(int state)
+{
+ int ret = 0;
+
+ if (!cpufreq_driver->low_level_boost)
+ return -ENODEV;
+
+ if (cpufreq_driver->boost_en != state) {
+ ret = cpufreq_driver->low_level_boost(state);
+ if (ret) {
+ pr_err("%s: BOOST cannot %sable low level code (%d)\n",
+ __func__, state ? "en" : "dis", ret);
+ return ret;
+ }
+ }
+
+ pr_debug("%s: cpufreq BOOST %sabled\n", __func__, state ? "en" : "dis");
+
+ return 0;
+}
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -1947,6 +2010,12 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+
+ if (cpufreq_driver->low_level_boost && cpufreq_boost_sysfs_defined) {
+ sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
+ cpufreq_boost_sysfs_defined = 0;
+ }
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a7966..4e4f692 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -20,6 +20,27 @@
* FREQUENCY TABLE HELPERS *
*********************************************************************/
+unsigned int
+cpufreq_frequency_table_max(struct cpufreq_frequency_table *freq_table,
+ int boost)
+{
+ int i = 0, boost_freq_max = 0, freq_max = 0;
+
+ for (; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ if (freq_table[i].index == CPUFREQ_BOOST_FREQ) {
+ if (freq_table[i].frequency > boost_freq_max)
+ boost_freq_max = freq_table[i].frequency;
+ } else {
+ if (freq_table[i].frequency > freq_max)
+ freq_max = freq_table[i].frequency;
+ }
+ }
+
+ return boost ? boost_freq_max : freq_max;
+
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_max);
+
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
@@ -171,7 +192,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ int show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,22 +208,53 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ if (show_boost)
+ if (table[i].index != CPUFREQ_BOOST_FREQ)
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
return count;
+}
+/**
+ * show_available_normal_freqs - show normal boost frequencies for
+ * the specified CPU
+ */
+static ssize_t show_available_normal_freqs(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 0);
}
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
.attr = { .name = "scaling_available_frequencies",
.mode = 0444,
},
- .show = show_available_freqs,
+ .show = show_available_normal_freqs,
};
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t show_available_boost_freqs(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 1);
+}
+
+struct freq_attr cpufreq_freq_attr_boost_available_freqs = {
+ .attr = { .name = "scaling_boost_frequencies",
+ .mode = 0444,
+ },
+ .show = show_available_boost_freqs,
+};
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_boost_available_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 037d36a..d045da2 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -262,6 +262,10 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_en;
+ int (*low_level_boost) (int state);
};
/* flags */
@@ -403,6 +407,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST_FREQ ~2
+
struct cpufreq_frequency_table {
unsigned int index; /* any */
unsigned int frequency; /* kHz - doesn't need to be in ascending
@@ -421,11 +428,16 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+unsigned int
+cpufreq_frequency_table_max(struct cpufreq_frequency_table *freq_table, int);
+int cpufreq_boost_trigger_state(int state);
+
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_boost_available_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
Global flags (boost_enabled and boost_supported) were replaced with boost_en
flag and low_level_boost pointer presence at cpufreq driver structure.
The _store_boost() function has been redesigned to be used as low_level_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
---
drivers/cpufreq/acpi-cpufreq.c | 72 +++++++++++++++-------------------------
1 file changed, 26 insertions(+), 46 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 11b8b4b..a15c999 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,20 +132,11 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
+ if ((val && acpi_cpufreq_driver.boost_en) ||
+ (!val && !acpi_cpufreq_driver.boost_en))
+ return 0;
get_online_cpus();
@@ -154,38 +144,39 @@ static ssize_t _store_boost(const char *buf, size_t count)
put_online_cpus();
- boost_enabled = val;
+ acpi_cpufreq_driver.boost_en = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
+ return 0;
}
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_boost(const char *buf, size_t count)
{
- return _store_boost(buf, count);
-}
+ int ret;
+ unsigned long val = 0;
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
-}
+ if (!acpi_cpufreq_driver.low_level_boost)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
+ _store_boost((int) val);
+
+ return count;
+}
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_en);
}
static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
@@ -571,7 +562,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_en, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -930,33 +921,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
+ acpi_cpufreq_driver.low_level_boost = &_store_boost;
+ acpi_cpufreq_driver.boost_en = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_en, cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (sysfs_create_file(cpufreq_global_kobject, &(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
--
1.7.10.4
The struct cpufreq_driver has been extended to embrace the information
related to boost support.
When "boost_mode" device tree attribute is defined for a platform, the
low_level_boost pointer is filled with proper address. The
.low_level_boost field filled to NULL, indicates that boost is not
supported.
Operations of exynos_cpufreq_boost_trigger() function are protected with
"local" mutex.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
---
drivers/cpufreq/exynos-cpufreq.c | 49 ++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 3197d88..8cf5636 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -33,6 +33,7 @@ static struct cpufreq_freqs freqs;
static unsigned int locking_frequency;
static bool frequency_locked;
static DEFINE_MUTEX(cpufreq_lock);
+static struct cpufreq_cpuinfo *cpufreq_cpu_info;
static int exynos_verify_speed(struct cpufreq_policy *policy)
{
@@ -154,6 +155,7 @@ out:
return ret;
}
+static struct cpufreq_driver exynos_driver;
static int exynos_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
@@ -244,6 +246,9 @@ static struct notifier_block exynos_cpufreq_nb = {
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ unsigned int max_freq;
+ int ret;
+
policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu);
cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
@@ -253,7 +258,19 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpumask_setall(policy->cpus);
- return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+ if (ret)
+ return ret;
+
+ if (exynos_driver.low_level_boost) {
+ /* disable boost by default */
+ max_freq = cpufreq_frequency_table_max(exynos_info->freq_table,
+ 0);
+ policy->cpuinfo.max_freq = policy->max = max_freq;
+ cpufreq_cpu_info = &policy->cpuinfo;
+ }
+
+ return 0;
}
static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -264,9 +281,32 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_boost_available_freqs,
NULL,
};
+static int exynos_cpufreq_boost_trigger(int state)
+{
+ struct cpufreq_policy *policy = container_of(cpufreq_cpu_info,
+ struct cpufreq_policy,
+ cpuinfo);
+ unsigned int max_freq;
+
+ mutex_lock(&cpufreq_lock);
+ exynos_driver.boost_en = state;
+
+ /* Recalculate maximal frequency */
+ max_freq = cpufreq_frequency_table_max(exynos_info->freq_table,
+ exynos_driver.boost_en);
+
+ if (policy->max != max_freq)
+ policy->cpuinfo.max_freq = policy->max = max_freq;
+
+ mutex_unlock(&cpufreq_lock);
+
+ return 0;
+}
+
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
.verify = exynos_verify_speed,
@@ -275,7 +315,7 @@ static struct cpufreq_driver exynos_driver = {
.init = exynos_cpufreq_cpu_init,
.exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
- .attr = exynos_cpufreq_attr,
+ .attr = exynos_cpufreq_attr,
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
@@ -359,6 +399,8 @@ static struct of_device_id exynos_cpufreq_of_match[] __initconst = {
static int __init exynos_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
+
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -391,6 +433,9 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
}
locking_frequency = exynos_getspeed(0);
+ if (of_property_read_bool(node, "boost_mode"))
+ exynos_driver.low_level_boost =
+ &exynos_cpufreq_boost_trigger;
register_pm_notifier(&exynos_cpufreq_nb);
--
1.7.10.4
Hi,
Change subject to: "cpufreq: Add boost frequency support in core"
On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> This commit adds support for software based frequency boosting.
No. It adds support for both software and hardware boosting. So just
write: This commit adds boost frequency support in cpufreq core (Hardware
& Software).
> Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
> its normal condition limits. Such a change shall be only done for a short
s/condition/operation
s/change/mode
s/done/used
> time.
>
> Overclocking (boost) support is essentially provided by platform
> dependent cpufreq driver.
>
> This commit unifies support for SW and HW (Intel) over clocking solutions
> in the core cpufreq driver. Previously the "boost" sysfs attribute was
> defined at acpi driver code.
> By default boost is disabled. One global attribute is available at:
> /sys/devices/system/cpu/cpufreq/boost.
Enter a blank line here.
> It only shows up when cpufreq driver supports overclocking.
> Under the hood frequencies dedicated for boosting are marked with a
> special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
> It is the user's concern to enable/disable overclocking with proper call to
> sysfs.
Good.
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v2:
> - Removal of cpufreq_boost structure and move its fields to cpufreq_driver
> structure
> - Flag to indicate if global boost attribute is already defined
> - Extent the pr_{err|debbug} functions to show current function names
> ---
You don't have to manually add "---" here. Just keep a blank line instead.
> drivers/cpufreq/cpufreq.c | 69 ++++++++++++++++++++++++++++++++++++++++++
> drivers/cpufreq/freq_table.c | 57 ++++++++++++++++++++++++++++++++--
> include/linux/cpufreq.h | 12 ++++++++
> 3 files changed, 136 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 1b8a48e..98ba5f1 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -40,6 +40,7 @@
> * also protects the cpufreq_cpu_data array.
> */
> static struct cpufreq_driver *cpufreq_driver;
> +static bool cpufreq_boost_sysfs_defined;
> static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> #ifdef CONFIG_HOTPLUG_CPU
> /* This one keeps track of the previously set governor of a removed CPU */
> @@ -315,6 +316,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
> /*********************************************************************
> * SYSFS INTERFACE *
> *********************************************************************/
> +ssize_t show_boost_status(struct kobject *kobj,
> + struct attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%d\n", cpufreq_driver->boost_en);
This isn't correct. It shows if cpufreq driver supports boost or
not and it should show if boost is enabled from sysfs when
cpufreq driver supports boost.
> +}
> +
> +static ssize_t store_boost_status(struct kobject *kobj, struct attribute *attr,
> + const char *buf, size_t count)
> +{
> + int ret, enable;
> +
> + ret = sscanf(buf, "%d", &enable);
> + if (ret != 1 || enable < 0 || enable > 1)
> + return -EINVAL;
> +
> + if (cpufreq_boost_trigger_state(enable)) {
> + pr_err("%s: Cannot %sable boost!\n", __func__,
> + enable ? "en" : "dis");
%sable doesn't look very much readable. Use complete strings:
"enable" and "disable".
> + return -EINVAL;
> + }
> +
> + return count;
> +}
> +
> +static struct global_attr global_boost = __ATTR(boost, 0644,
> + show_boost_status,
> + store_boost_status);
User define_one_global_rw.
> static struct cpufreq_governor *__find_governor(const char *str_governor)
> {
> @@ -754,6 +782,17 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
Why not do this in cpufreq_register_driver()?
> goto err_out_kobj_put;
> drv_attr++;
> }
> + if (cpufreq_driver->low_level_boost && !cpufreq_boost_sysfs_defined) {
I thought low_level_boost() is a function which will only be supported
for drivers
using hardware boost feature, like intel. And so we must have used boost_en
here.
> + ret = sysfs_create_file(cpufreq_global_kobject,
> + &(global_boost.attr));
cpufreq_sysfs_create_file(), check 2361be23666232dbb4851a527f466c4cbf5340fc
for details.
> + if (ret) {
> + pr_err("%s: cannot register global boost sysfs file\n",
> + __func__);
> + goto err_out_kobj_put;
> + }
> + cpufreq_boost_sysfs_defined = 1;
> + }
> +
> if (cpufreq_driver->get) {
> ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
> if (ret)
> @@ -1853,6 +1892,30 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
> };
>
> /*********************************************************************
> + * BOOST *
> + *********************************************************************/
> +int cpufreq_boost_trigger_state(int state)
> +{
> + int ret = 0;
> +
> + if (!cpufreq_driver->low_level_boost)
> + return -ENODEV;
I am certainly not aligned with your design. What's the
use of this field? And please update documentation too for these
new entries in cpufreq_driver structure.
> + if (cpufreq_driver->boost_en != state) {
So, you are using boost_en to see if boost is enabled from sysfs?
Then you have put it at wrong place.
I thought there would be three variables:
- cpufreq_driver->boost_supported: boost is enabled for driver
- cpufreq_driver->low_level_boost(): to set desired boost state
(Only for hardware boosting)
- boost_enabled: global variable in cpufreq.c file, used only if
cpufreq_driver->boost_supported is true.
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index d7a7966..4e4f692 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -20,6 +20,27 @@
> * FREQUENCY TABLE HELPERS *
> *********************************************************************/
>
> +unsigned int
> +cpufreq_frequency_table_max(struct cpufreq_frequency_table *freq_table,
> + int boost)
> +{
> + int i = 0, boost_freq_max = 0, freq_max = 0;
> +
> + for (; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
> + if (freq_table[i].index == CPUFREQ_BOOST_FREQ) {
> + if (freq_table[i].frequency > boost_freq_max)
> + boost_freq_max = freq_table[i].frequency;
Do above only when boost==true and below when boost==false.
> + } else {
> + if (freq_table[i].frequency > freq_max)
> + freq_max = freq_table[i].frequency;
> + }
> + }
> +
> + return boost ? boost_freq_max : freq_max;
> +
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_max);
> +
> int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
> struct cpufreq_frequency_table *table)
> {
> @@ -171,7 +192,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
> /**
> * show_available_freqs - show available frequencies for the specified CPU
> */
> -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
> + int show_boost)
> {
> unsigned int i = 0;
> unsigned int cpu = policy->cpu;
> @@ -186,22 +208,53 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
> if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> continue;
> + if (show_boost)
> + if (table[i].index != CPUFREQ_BOOST_FREQ)
> + continue;
> +
Looks wrong. You will show boost freqs when show_boost is false.
> count += sprintf(&buf[count], "%d ", table[i].frequency);
> }
> count += sprintf(&buf[count], "\n");
>
> return count;
> +}
>
> +/**
> + * show_available_normal_freqs - show normal boost frequencies for
> + * the specified CPU
> + */
> +static ssize_t show_available_normal_freqs(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 0);
> }
>
> struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> .attr = { .name = "scaling_available_frequencies",
> .mode = 0444,
> },
> - .show = show_available_freqs,
> + .show = show_available_normal_freqs,
> };
> EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
>
> +/**
> + * show_available_boost_freqs - show available boost frequencies for
> + * the specified CPU
> + */
> +static ssize_t show_available_boost_freqs(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 1);
> +}
> +
> +struct freq_attr cpufreq_freq_attr_boost_available_freqs = {
> + .attr = { .name = "scaling_boost_frequencies",
> + .mode = 0444,
> + },
> + .show = show_available_boost_freqs,
> +};
> +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_boost_available_freqs);
> +
Code redundancy can be reduced by creating a macro for declaring
**_availabe_freqs, its attributes and export symbol.
> /*
> * if you use these, you must assure that the frequency table is valid
> * all the time between get_attr and put_attr!
With this patch alone, we would be using boost frequencies even in
normal cases where we haven't enabled boost.
On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to include
> common code.
To be honest, I haven't given a review to patches 2/3 and 3/3 as I am
concerned more about 1/3.
Maybe you can just send v3 of 1/3. 2/3 and 3/3 can be sent when we have
finalized 2/3 and 3/3 's version.
Hi Viresh,
> On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> > This patch series introduces support for CPU overclocking technique
> > called Boost.
> >
> > It is a follow up of a LAB governor proposal. Boost is a LAB
> > component:
> > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> >
> > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > software oriented one (like the one done at Exynos).
> > For this reason cpufreq/freq_table code has been reorganized to
> > include common code.
>
> To be honest, I haven't given a review to patches 2/3 and 3/3 as I am
> concerned more about 1/3.
As you pointed out in the other mail 1/3 has its own issues, but I
think that patches 2/3 and 3/3 are an integral part of the boost
support and bring better overall overview to the design.
>
> Maybe you can just send v3 of 1/3. 2/3 and 3/3 can be sent when we
> have finalized 2/3 and 3/3 's version.
I'd opt for sending the whole patchset (it shouldn't be so difficult to
adjust those patches), since it is easier for me to test.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 June 2013 11:30, Lukasz Majewski <[email protected]> wrote:
> As you pointed out in the other mail 1/3 has its own issues, but I
> think that patches 2/3 and 3/3 are an integral part of the boost
> support and bring better overall overview to the design.
Yes they are. Undoubtedly.
>> Maybe you can just send v3 of 1/3. 2/3 and 3/3 can be sent when we
>> have finalized 2/3 and 3/3 's version.
>
> I'd opt for sending the whole patchset (it shouldn't be so difficult to
> adjust those patches), since it is easier for me to test.
Okay.
Hi Viresh,
> Hi,
>
> Change subject to: "cpufreq: Add boost frequency support in core"
Ok.
>
> On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> > This commit adds support for software based frequency boosting.
>
> No. It adds support for both software and hardware boosting. So just
> write: This commit adds boost frequency support in cpufreq core
> (Hardware & Software).
Ok.
>
> > Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
> > its normal condition limits. Such a change shall be only done for a
> > short
>
> s/condition/operation
> s/change/mode
> s/done/used
>
Ok.
> > time.
> >
> > Overclocking (boost) support is essentially provided by platform
> > dependent cpufreq driver.
> >
> > This commit unifies support for SW and HW (Intel) over clocking
> > solutions in the core cpufreq driver. Previously the "boost" sysfs
> > attribute was defined at acpi driver code.
> > By default boost is disabled. One global attribute is available at:
> > /sys/devices/system/cpu/cpufreq/boost.
>
> Enter a blank line here.
Ok
>
> > It only shows up when cpufreq driver supports overclocking.
> > Under the hood frequencies dedicated for boosting are marked with a
> > special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
> > It is the user's concern to enable/disable overclocking with proper
> > call to sysfs.
>
> Good.
>
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > ---
^^^^
[*] this --- was added manually by me.
> > Changes for v2:
> > - Removal of cpufreq_boost structure and move its fields to
> > cpufreq_driver structure
> > - Flag to indicate if global boost attribute is already defined
> > - Extent the pr_{err|debbug} functions to show current function
> > names ---
>
> You don't have to manually add "---" here. Just keep a blank line
> instead.
One "---" is added by git automatically. The [*] was added to distinct
the changelog from rest of the commit. At least older versions of GIT
required this to not include changelog to commit messages.
>
> > drivers/cpufreq/cpufreq.c | 69
> > ++++++++++++++++++++++++++++++++++++++++++
> > drivers/cpufreq/freq_table.c | 57
> > ++++++++++++++++++++++++++++++++-- include/linux/cpufreq.h |
> > 12 ++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 1b8a48e..98ba5f1 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -40,6 +40,7 @@
> > * also protects the cpufreq_cpu_data array.
> > */
> > static struct cpufreq_driver *cpufreq_driver;
> > +static bool cpufreq_boost_sysfs_defined;
> > static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> > #ifdef CONFIG_HOTPLUG_CPU
> > /* This one keeps track of the previously set governor of a
> > removed CPU */ @@ -315,6 +316,33 @@
> > EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /*********************************************************************
> > * SYSFS
> > INTERFACE *
> > *********************************************************************/
> > +ssize_t show_boost_status(struct kobject *kobj,
> > + struct attribute *attr, char *buf)
> > +{
> > + return sprintf(buf, "%d\n", cpufreq_driver->boost_en);
>
> This isn't correct. It shows if cpufreq driver supports boost or
> not and it should show if boost is enabled from sysfs when
> cpufreq driver supports boost.
The cpufreq_driver->low_level_boost() is only valid when cpufreq driver
supports boost. Otherwise it is NULL. Thereof you will not see those
attributes exported to /sysfs until cpufreq driver supports boost.
When "boost" attribute is exported - then it returns state of boosting
(if it is enabled or not).
>
> > +}
> > +
> > +static ssize_t store_boost_status(struct kobject *kobj, struct
> > attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + int ret, enable;
> > +
> > + ret = sscanf(buf, "%d", &enable);
> > + if (ret != 1 || enable < 0 || enable > 1)
> > + return -EINVAL;
> > +
> > + if (cpufreq_boost_trigger_state(enable)) {
> > + pr_err("%s: Cannot %sable boost!\n", __func__,
> > + enable ? "en" : "dis");
>
> %sable doesn't look very much readable. Use complete strings:
> "enable" and "disable".
Ok.
>
> > + return -EINVAL;
> > + }
> > +
> > + return count;
> > +}
> > +
> > +static struct global_attr global_boost = __ATTR(boost, 0644,
> > + show_boost_status,
> > + store_boost_status);
>
> User define_one_global_rw.
Ok, will reuse available macros (this code was taken directly from
acpi-cpufreq.c file).
>
> > static struct cpufreq_governor *__find_governor(const char
> > *str_governor) {
> > @@ -754,6 +782,17 @@ static int cpufreq_add_dev_interface(unsigned
> > int cpu,
>
> Why not do this in cpufreq_register_driver()?
Good point. I will move this code to cpufreq_register_driver.
>
> > goto err_out_kobj_put;
> > drv_attr++;
> > }
> > + if (cpufreq_driver->low_level_boost
> > && !cpufreq_boost_sysfs_defined) {
>
> I thought low_level_boost() is a function which will only be supported
> for drivers
> using hardware boost feature, like intel.
I think that we shall give users some flexibility and don't assume that
low_level_boost is only used for one solution/vendor.
It is also needed with software controlled boost. Please refer to patch
3/3.
> And so we must have used
> boost_en here.
boost_en has two meanings:
0 - either boost disabled or not supported (when low_level_boost=NULL).
1 - boost is enabled.
>
> > + ret = sysfs_create_file(cpufreq_global_kobject,
> > + &(global_boost.attr));
>
> cpufreq_sysfs_create_file(), check
> 2361be23666232dbb4851a527f466c4cbf5340fc for details.
Ok, I will rebase those changes to newest
kernel/git/rafael/linux-pm.git ,branch
kernel_pm/pm-cpufreq
>
> > + if (ret) {
> > + pr_err("%s: cannot register global boost
> > sysfs file\n",
> > + __func__);
> > + goto err_out_kobj_put;
> > + }
> > + cpufreq_boost_sysfs_defined = 1;
> > + }
> > +
> > if (cpufreq_driver->get) {
> > ret = sysfs_create_file(&policy->kobj,
> > &cpuinfo_cur_freq.attr); if (ret)
> > @@ -1853,6 +1892,30 @@ static struct notifier_block __refdata
> > cpufreq_cpu_notifier = { };
> >
> > /*********************************************************************
> > + *
> > BOOST *
> > +
> > *********************************************************************/
> > +int cpufreq_boost_trigger_state(int state) +{
> > + int ret = 0;
> > +
> > + if (!cpufreq_driver->low_level_boost)
> > + return -ENODEV;
>
> I am certainly not aligned with your design. What's the
> use of this field?
I had to rewrite a bit :-) patches since we decided to drop struct
cpufreq_boost.
I've added two fields to cpufreq_driver:
- low_level_boost:
* When boost is not supported (default) it is set to NULL. This
field has two purposes: Indicates if boost is available on
the system and provides address of low level callback
* When cpufreq driver assigns pointer to this field,
it means that it is supported
- boost_en:
* It shows if boost is enabled or disabled/not supported to the
rest of the system.
> And please update documentation too for these
> new entries in cpufreq_driver structure.
Ok I will extend it.
>
> > + if (cpufreq_driver->boost_en != state) {
>
> So, you are using boost_en to see if boost is enabled from sysfs?
> Then you have put it at wrong place.
I check if boost is already enabled.
>
> I thought there would be three variables:
> - cpufreq_driver->boost_supported: boost is enabled for driver
For this purpose I check the low_level_boost pointer if it's NULL or
not.
> - cpufreq_driver->low_level_boost(): to set desired boost state
> (Only for hardware boosting)
It has two purposes (as described above) and can be used (defined) by
software and hardware boost solutions.
> - boost_enabled: global variable in cpufreq.c file, used only if
> cpufreq_driver->boost_supported is true.
I think that boost enabled flag shall be defined at cpufreq driver
(please look into acpi_cpufreq.c - which used another set of global
flags).
It will then provide one flag for cpufreq.c (core) and drivers.
However I've added one global flag: cpufreq_boost_sysfs_defined
which indicates if /sys/devices/system/cpu/cpufreq/boost attribute has
been already defined (to prevent multiple definitions attempts).
>
>
> > diff --git a/drivers/cpufreq/freq_table.c
> > b/drivers/cpufreq/freq_table.c index d7a7966..4e4f692 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -20,6 +20,27 @@
> > * FREQUENCY TABLE
> > HELPERS *
> > *********************************************************************/
> >
> > +unsigned int
> > +cpufreq_frequency_table_max(struct cpufreq_frequency_table
> > *freq_table,
> > + int boost)
> > +{
> > + int i = 0, boost_freq_max = 0, freq_max = 0;
> > +
> > + for (; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
> > + if (freq_table[i].index == CPUFREQ_BOOST_FREQ) {
> > + if (freq_table[i].frequency >
> > boost_freq_max)
> > + boost_freq_max =
> > freq_table[i].frequency;
>
> Do above only when boost==true and below when boost==false.
Ok.
>
> > + } else {
> > + if (freq_table[i].frequency > freq_max)
> > + freq_max = freq_table[i].frequency;
> > + }
> > + }
> > +
> > + return boost ? boost_freq_max : freq_max;
> > +
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_max);
> > +
> > int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
> > struct cpufreq_frequency_table
> > *table) {
> > @@ -171,7 +192,8 @@ static DEFINE_PER_CPU(struct
> > cpufreq_frequency_table *, cpufreq_show_table); /**
> > * show_available_freqs - show available frequencies for the
> > specified CPU */
> > -static ssize_t show_available_freqs(struct cpufreq_policy *policy,
> > char *buf) +static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf,
> > + int show_boost)
> > {
> > unsigned int i = 0;
> > unsigned int cpu = policy->cpu;
> > @@ -186,22 +208,53 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf) for (i = 0;
> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
> > + if (show_boost)
> > + if (table[i].index != CPUFREQ_BOOST_FREQ)
> > + continue;
> > +
>
> Looks wrong. You will show boost freqs when show_boost is false.
My purpose here is to display frequencies only tagged with
CPUFREQ_BOOST_FREQ and when show_boost is true.
When show_boost is false, the operation of the function is unchanged.
>
> > count += sprintf(&buf[count], "%d ",
> > table[i].frequency); }
> > count += sprintf(&buf[count], "\n");
> >
> > return count;
> > +}
> >
> > +/**
> > + * show_available_normal_freqs - show normal boost frequencies for
> > + * the specified CPU
> > + */
> > +static ssize_t show_available_normal_freqs(struct cpufreq_policy
> > *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 0);
> > }
> >
> > struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> > .attr = { .name = "scaling_available_frequencies",
> > .mode = 0444,
> > },
> > - .show = show_available_freqs,
> > + .show = show_available_normal_freqs,
> > };
> > EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
> >
> > +/**
> > + * show_available_boost_freqs - show available boost frequencies
> > for
> > + * the specified CPU
> > + */
> > +static ssize_t show_available_boost_freqs(struct cpufreq_policy
> > *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 1);
> > +}
> > +
> > +struct freq_attr cpufreq_freq_attr_boost_available_freqs = {
> > + .attr = { .name = "scaling_boost_frequencies",
> > + .mode = 0444,
> > + },
> > + .show = show_available_boost_freqs,
> > +};
> > +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_boost_available_freqs);
> > +
>
> Code redundancy can be reduced by creating a macro for declaring
> **_availabe_freqs, its attributes and export symbol.
Yes, you are right here. Those two structures only differ with
different names.
>
> > /*
> > * if you use these, you must assure that the frequency table is
> > valid
> > * all the time between get_attr and put_attr!
>
> With this patch alone, we would be using boost frequencies even in
> normal cases where we haven't enabled boost.
Correct me if I'm wrong here, but the
cpufreq_freq_attr_boost_available_freqs will be added to cpufreq
driver's freq_attr table (i.e. *exynos_cpufreq_attr[]).
It is cpufreq driver's responsibility to add this attribute. By default
all other drivers add only cpufreq_freq_attr_boost_available_freqs.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 June 2013 13:09, Lukasz Majewski <[email protected]> wrote:
> Hi Viresh,
Hi Lukasz,
>> Hi,
Please don't remove the line which says, who wrote last mail at what time.
These >, >>, >>>, >>>>, ... have a meaning. They help us understand who
wrote what in bottom posting. And as you removed my line, nobody can see
who wrote above "Hi" to you :)
>> You don't have to manually add "---" here. Just keep a blank line
>> instead.
>
> One "---" is added by git automatically. The [*] was added to distinct
> the changelog from rest of the commit. At least older versions of GIT
> required this to not include changelog to commit messages.
You don't have to add an extra "---" line. Just write your changelog
after "---" added by git and give a blank line between your last
changelog line and below ones (probably just to make it more
readable and not a must, but i am not sure).
>> > drivers/cpufreq/cpufreq.c | 69
>> > ++++++++++++++++++++++++++++++++++++++++++
>> > drivers/cpufreq/freq_table.c | 57
>> > ++++++++++++++++++++++++++++++++-- include/linux/cpufreq.h |
>> > 12 ++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
> I think that we shall give users some flexibility and don't assume that
> low_level_boost is only used for one solution/vendor.
>
> It is also needed with software controlled boost. Please refer to patch
> 3/3.
You didn't get me. I am not asking to keep it only for Intel. But keep
this variable as is (s/low_level_boost/set_boost_freq), and make it
optional. So, few drivers can implement it but not everybody is required
to.
So, Add another variable: boost_supported, which will tell cpufreq core
that boost is supported by governor or not.
And a global variable in cpufreq.c boost_enabled to track status of
what user has requested.
> However I've added one global flag: cpufreq_boost_sysfs_defined
> which indicates if /sys/devices/system/cpu/cpufreq/boost attribute has
> been already defined (to prevent multiple definitions attempts).
You don't need this variable anymore as sysfs create file is now
moved to cpufreq_register_driver(), so this can't be called twice.
>> > char *buf) +static ssize_t show_available_freqs(struct
>> > cpufreq_policy *policy, char *buf,
>> > + int show_boost)
>> > {
>> > unsigned int i = 0;
>> > unsigned int cpu = policy->cpu;
>> > @@ -186,22 +208,53 @@ static ssize_t show_available_freqs(struct
>> > cpufreq_policy *policy, char *buf) for (i = 0;
>> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
>> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
>> > + if (show_boost)
>> > + if (table[i].index != CPUFREQ_BOOST_FREQ)
>> > + continue;
>> > +
>>
>> Looks wrong. You will show boost freqs when show_boost is false.
>
> My purpose here is to display frequencies only tagged with
> CPUFREQ_BOOST_FREQ and when show_boost is true.
>
> When show_boost is false, the operation of the function is unchanged.
Which is wrong. When show_boost is false, it means that user don't
want to see boost frequencies and so you should skip them.
>> With this patch alone, we would be using boost frequencies even in
>> normal cases where we haven't enabled boost.
>
> Correct me if I'm wrong here, but the
> cpufreq_freq_attr_boost_available_freqs will be added to cpufreq
> driver's freq_attr table (i.e. *exynos_cpufreq_attr[]).
> It is cpufreq driver's responsibility to add this attribute. By default
> all other drivers add only cpufreq_freq_attr_boost_available_freqs.
You are just talking about showing boost freqs in sysfs. I am talking
about the frequencies that governors will select when boost is
disabled from sysfs. Because we don't skip boost frequencies in
target() routines, we will set them as and when governor requests
them.
On Wed, 12 Jun 2013 13:39:18 +0530, Viresh Kumar wrote:
Hi Viresh,
> On 12 June 2013 13:09, Lukasz Majewski <[email protected]> wrote:
> > Hi Viresh,
>
> Hi Lukasz,
>
> >> Hi,
>
> Please don't remove the line which says, who wrote last mail at what
> time. These >, >>, >>>, >>>>, ... have a meaning. They help us
> understand who wrote what in bottom posting. And as you removed my
> line, nobody can see who wrote above "Hi" to you :)
Ok, mailer adjusted.
>
> >> You don't have to manually add "---" here. Just keep a blank line
> >> instead.
> >
> > One "---" is added by git automatically. The [*] was added to
> > distinct the changelog from rest of the commit. At least older
> > versions of GIT required this to not include changelog to commit
> > messages.
>
> You don't have to add an extra "---" line. Just write your changelog
> after "---" added by git and give a blank line between your last
> changelog line and below ones (probably just to make it more
> readable and not a must, but i am not sure).
I got your point. If you prefer, I will stick to it. No problem.
As a side note:
In the other open source project (u-boot) we use the pattern which I've
used previously. It has one big advantage - I can edit change log at
git gui (just below sign-of-by). It is simply more convenient for
me :-). Those changes between "---" are simply skipped by git am
afterwards.
>
> >> > drivers/cpufreq/cpufreq.c | 69
> >> > ++++++++++++++++++++++++++++++++++++++++++
> >> > drivers/cpufreq/freq_table.c | 57
> >> > ++++++++++++++++++++++++++++++++-- include/linux/cpufreq.h |
> >> > 12 ++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
>
> > I think that we shall give users some flexibility and don't assume
> > that low_level_boost is only used for one solution/vendor.
> >
> > It is also needed with software controlled boost. Please refer to
> > patch 3/3.
>
> You didn't get me. I am not asking to keep it only for Intel. But keep
> this variable as is (s/low_level_boost/set_boost_freq), and make it
> optional. So, few drivers can implement it but not everybody is
> required to.
The low_level_boost (set_boost_freq)[*] is optional. However it seems to
me, that the burden of changing available set of frequencies (when
boost is enabled) must be put to cpufreq driver anyway.
Without this function [*] defined, we cannot enable frequency boosting.
>
> So, Add another variable: boost_supported, which will tell cpufreq
> core that boost is supported by governor or not.
^^^^^^^shouldn't it be cpufreq driver?
Ok, boost_supported seems needed. In my opinion it shall be defined at
cpufreq_driver structure (since it provides boosting infrastructure
anyway).
>
> And a global variable in cpufreq.c boost_enabled to track status of
> what user has requested.
I think, that boost_enable shall be also defined at cpufreq driver (as
proposed in the patch). We keep pointer to cpufreq driver at cpufreq.c
anyway. Moreover, boost_enable flag is already defined at
acpi-cpufreq.c (as static). We will have two flags for the same
purpose.
>
> > However I've added one global flag: cpufreq_boost_sysfs_defined
> > which indicates if /sys/devices/system/cpu/cpufreq/boost attribute
> > has been already defined (to prevent multiple definitions attempts).
>
> You don't need this variable anymore as sysfs create file is now
> moved to cpufreq_register_driver(), so this can't be called twice.
Yes, in this situation the cpufreq_boost_sysfs_defined flag is
redundant.
>
> >> > char *buf) +static ssize_t show_available_freqs(struct
> >> > cpufreq_policy *policy, char *buf,
> >> > + int show_boost)
> >> > {
> >> > unsigned int i = 0;
> >> > unsigned int cpu = policy->cpu;
> >> > @@ -186,22 +208,53 @@ static ssize_t show_available_freqs(struct
> >> > cpufreq_policy *policy, char *buf) for (i = 0;
> >> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
> >> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
> >> > + if (show_boost)
> >> > + if (table[i].index != CPUFREQ_BOOST_FREQ)
> >> > + continue;
> >> > +
> >>
> >> Looks wrong. You will show boost freqs when show_boost is false.
> >
> > My purpose here is to display frequencies only tagged with
> > CPUFREQ_BOOST_FREQ and when show_boost is true.
> >
> > When show_boost is false, the operation of the function is
> > unchanged.
>
> Which is wrong. When show_boost is false, it means that user don't
> want to see boost frequencies and so you should skip them.
So we want as follows:
show_boost = 1 ---> show only frequencies tagged as CPUFREQ_BOOST_FREQ
show_boost = 0 ---> show only "normal" (non boost) frequencies
>
> >> With this patch alone, we would be using boost frequencies even in
> >> normal cases where we haven't enabled boost.
> >
> > Correct me if I'm wrong here, but the
> > cpufreq_freq_attr_boost_available_freqs will be added to cpufreq
> > driver's freq_attr table (i.e. *exynos_cpufreq_attr[]).
> > It is cpufreq driver's responsibility to add this attribute. By
> > default all other drivers add only
> > cpufreq_freq_attr_boost_available_freqs.
>
> You are just talking about showing boost freqs in sysfs. I am talking
> about the frequencies that governors will select when boost is
> disabled from sysfs. Because we don't skip boost frequencies in
> target() routines, we will set them as and when governor requests
> them.
I think, that it is the main issue here and it shall be cleared out:
Frequencies marked as: CPUFREQ_BOOST_FREQ are added permanently to the
freq_table.
That is the distinction to the original overclocking patch posted with
LAB, where freq_boost structure was modified and boost frequencies were
either valid or invalid.
Then we can in SW control boost in two ways:
1. change policy->max value (to the maximal boost frequency) - as it is
done now (v3) at Exynos. This is the simple solution (patch 3/3)
2. Modify all freq_table helper functions to be aware of boost and
skip boost frequencies when boost_enable = 0. (as it was done at v2).
This requires code modification at freq_table.c and reevaluation of
policy.
Maybe you have any other idea?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 June 2013 14:39, Lukasz Majewski <[email protected]> wrote:
> On Wed, 12 Jun 2013 13:39:18 +0530, Viresh Kumar wrote:
>> On 12 June 2013 13:09, Lukasz Majewski <[email protected]> wrote:
>> You don't have to add an extra "---" line. Just write your changelog
>> after "---" added by git and give a blank line between your last
>> changelog line and below ones (probably just to make it more
>> readable and not a must, but i am not sure).
>
> I got your point. If you prefer, I will stick to it. No problem.
Its not how I prefer it, but how everybody does it :)
> As a side note:
>
> In the other open source project (u-boot) we use the pattern which I've
> used previously. It has one big advantage - I can edit change log at
> git gui (just below sign-of-by). It is simply more convenient for
> me :-). Those changes between "---" are simply skipped by git am
> afterwards.
Yes, I am still asking you to follow the same steps:
git send-email --annotate ***patches***
and then write whatever you don't want to be logged by git am after
the "---" already present in the patch.
>> >> > drivers/cpufreq/cpufreq.c | 69
>> >> > ++++++++++++++++++++++++++++++++++++++++++
>> >> > drivers/cpufreq/freq_table.c | 57
>> >> > ++++++++++++++++++++++++++++++++-- include/linux/cpufreq.h |
>> >> > 12 ++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
>>
>> > I think that we shall give users some flexibility and don't assume
>> > that low_level_boost is only used for one solution/vendor.
>> >
>> > It is also needed with software controlled boost. Please refer to
>> > patch 3/3.
>>
>> You didn't get me. I am not asking to keep it only for Intel. But keep
>> this variable as is (s/low_level_boost/set_boost_freq), and make it
>> optional. So, few drivers can implement it but not everybody is
>> required to.
>
> The low_level_boost (set_boost_freq)[*] is optional. However it seems to
> me, that the burden of changing available set of frequencies (when
> boost is enabled) must be put to cpufreq driver anyway.
Driver shouldn't play with boost freqs at runtime. This has to be handled
by cpufreq core. The only thing cpufreq driver must be doing in
low_level_boost or set_boost_freq (as what I suggested it to be), is
to set the boost frequency requested by core. And so this routine would
only be defined by drivers that have a special way of setting boost
frequencies. For others ->target() routine should be able to set all
freqs, boost or non boost.
> Without this function [*] defined, we cannot enable frequency boosting.
why?
>> So, Add another variable: boost_supported, which will tell cpufreq
>> core that boost is supported by governor or not.
> ^^^^^^^shouldn't it be cpufreq driver?
Yeah, sorry :(
> Ok, boost_supported seems needed. In my opinion it shall be defined at
> cpufreq_driver structure (since it provides boosting infrastructure
> anyway).
that's what I asked.
>> And a global variable in cpufreq.c boost_enabled to track status of
>> what user has requested.
>
> I think, that boost_enable shall be also defined at cpufreq driver (as
> proposed in the patch).
Not really. Driver should only care about if it supports boost or not.
If it is enabled/disabled by sysfs or not should be kept inside core
in a global variable.
Moreover, if we have 5-6 cpufreq drivers compiled in (for multi-arch
compiled kernels), we will save memory wasted by this variable if
it is present in cpufreq_driver.
> Moreover, boost_enable flag is already defined at
> acpi-cpufreq.c (as static). We will have two flags for the same
> purpose.
No, we don't have to. Just expose another API from cpufreq core
to get status of boost.
> So we want as follows:
> show_boost = 1 ---> show only frequencies tagged as CPUFREQ_BOOST_FREQ
> show_boost = 0 ---> show only "normal" (non boost) frequencies
Yes.
>> You are just talking about showing boost freqs in sysfs. I am talking
>> about the frequencies that governors will select when boost is
>> disabled from sysfs. Because we don't skip boost frequencies in
>> target() routines, we will set them as and when governor requests
>> them.
>
> I think, that it is the main issue here and it shall be cleared out:
>
> Frequencies marked as: CPUFREQ_BOOST_FREQ are added permanently to the
> freq_table.
> That is the distinction to the original overclocking patch posted with
>> LAB, where freq_boost structure was modified and boost frequencies were
> either valid or invalid.
Yes.
> Then we can in SW control boost in two ways:
> 1. change policy->max value (to the maximal boost frequency) - as it is
> done now (v3) at Exynos. This is the simple solution (patch 3/3)
Drivers aren't supposed to set policy->max. It should be taken care
of by core or freq_table.c file.
> 2. Modify all freq_table helper functions to be aware of boost and
> skip boost frequencies when boost_enable = 0. (as it was done at v2).
> This requires code modification at freq_table.c and reevaluation of
> policy.
Yes, the core must be aware of it and must take the right decision
here. So, we need to take care of boost freq in freq_table.c
On Wednesday, June 12, 2013 09:39:38 AM Lukasz Majewski wrote:
> Hi Viresh,
>
> > Hi,
> >
> > Change subject to: "cpufreq: Add boost frequency support in core"
>
> Ok.
>
> >
> > On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> > > This commit adds support for software based frequency boosting.
> >
> > No. It adds support for both software and hardware boosting. So just
> > write: This commit adds boost frequency support in cpufreq core
> > (Hardware & Software).
>
> Ok.
> >
> > > Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
> > > its normal condition limits. Such a change shall be only done for a
> > > short
> >
> > s/condition/operation
> > s/change/mode
> > s/done/used
> >
>
> Ok.
>
> > > time.
> > >
> > > Overclocking (boost) support is essentially provided by platform
> > > dependent cpufreq driver.
> > >
> > > This commit unifies support for SW and HW (Intel) over clocking
> > > solutions in the core cpufreq driver. Previously the "boost" sysfs
> > > attribute was defined at acpi driver code.
> > > By default boost is disabled. One global attribute is available at:
> > > /sys/devices/system/cpu/cpufreq/boost.
> >
> > Enter a blank line here.
>
> Ok
>
> >
> > > It only shows up when cpufreq driver supports overclocking.
> > > Under the hood frequencies dedicated for boosting are marked with a
> > > special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
> > > It is the user's concern to enable/disable overclocking with proper
> > > call to sysfs.
> >
> > Good.
> >
> > > Signed-off-by: Lukasz Majewski <[email protected]>
> > > Signed-off-by: Myungjoo Ham <[email protected]>
> > >
> > > ---
> ^^^^
> [*] this --- was added manually by me.
>
> > > Changes for v2:
> > > - Removal of cpufreq_boost structure and move its fields to
> > > cpufreq_driver structure
> > > - Flag to indicate if global boost attribute is already defined
> > > - Extent the pr_{err|debbug} functions to show current function
> > > names ---
> >
> > You don't have to manually add "---" here. Just keep a blank line
> > instead.
>
> One "---" is added by git automatically. The [*] was added to distinct
> the changelog from rest of the commit. At least older versions of GIT
> required this to not include changelog to commit messages.
Which doesn't matter anyway. None of them will show up in git log, so don't
worry. :-)
[...]
>
> > And so we must have used
> > boost_en here.
>
> boost_en has two meanings:
> 0 - either boost disabled or not supported (when low_level_boost=NULL).
> 1 - boost is enabled.
Gosh, please don't do that. Use *two* flags, one meaning "supported" and the
second meaning "enabled".
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Wed, 12 Jun 2013 13:23:20 +0200, Rafael J. Wysocki wrote:
Hi Rafael,
> On Wednesday, June 12, 2013 09:39:38 AM Lukasz Majewski wrote:
> > Hi Viresh,
> >
> > > Hi,
> > >
> > > Change subject to: "cpufreq: Add boost frequency support in core"
> >
> > Ok.
> >
> > >
> > > On 11 June 2013 14:33, Lukasz Majewski <[email protected]>
> > > wrote:
> > > > This commit adds support for software based frequency boosting.
> > >
> > > No. It adds support for both software and hardware boosting. So
> > > just write: This commit adds boost frequency support in cpufreq
> > > core (Hardware & Software).
> >
> > Ok.
> > >
> > > > Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency
> > > > above its normal condition limits. Such a change shall be only
> > > > done for a short
> > >
> > > s/condition/operation
> > > s/change/mode
> > > s/done/used
> > >
> >
> > Ok.
> >
> > > > time.
> > > >
> > > > Overclocking (boost) support is essentially provided by platform
> > > > dependent cpufreq driver.
> > > >
> > > > This commit unifies support for SW and HW (Intel) over clocking
> > > > solutions in the core cpufreq driver. Previously the "boost"
> > > > sysfs attribute was defined at acpi driver code.
> > > > By default boost is disabled. One global attribute is available
> > > > at: /sys/devices/system/cpu/cpufreq/boost.
> > >
> > > Enter a blank line here.
> >
> > Ok
> >
> > >
> > > > It only shows up when cpufreq driver supports overclocking.
> > > > Under the hood frequencies dedicated for boosting are marked
> > > > with a special flag (CPUFREQ_BOOST_FREQ) at driver's frequency
> > > > table. It is the user's concern to enable/disable overclocking
> > > > with proper call to sysfs.
> > >
> > > Good.
> > >
> > > > Signed-off-by: Lukasz Majewski <[email protected]>
> > > > Signed-off-by: Myungjoo Ham <[email protected]>
> > > >
> > > > ---
> > ^^^^
> > [*] this --- was added manually by me.
> >
> > > > Changes for v2:
> > > > - Removal of cpufreq_boost structure and move its fields to
> > > > cpufreq_driver structure
> > > > - Flag to indicate if global boost attribute is already defined
> > > > - Extent the pr_{err|debbug} functions to show current function
> > > > names ---
> > >
> > > You don't have to manually add "---" here. Just keep a blank line
> > > instead.
> >
> > One "---" is added by git automatically. The [*] was added to
> > distinct the changelog from rest of the commit. At least older
> > versions of GIT required this to not include changelog to commit
> > messages.
>
> Which doesn't matter anyway. None of them will show up in git log,
> so don't worry. :-)
:-)
>
> [...]
>
> >
> > > And so we must have used
> > > boost_en here.
> >
> > boost_en has two meanings:
> > 0 - either boost disabled or not supported (when
> > low_level_boost=NULL). 1 - boost is enabled.
>
> Gosh, please don't do that. Use *two* flags, one meaning "supported"
> and the second meaning "enabled".
That was already pointed out by Viresh. I will stick to his
guidelines :-).
>
> Thanks,
> Rafael
>
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 12 Jun 2013 14:55:45 +0530, Viresh Kumar wrote:
> On 12 June 2013 14:39, Lukasz Majewski <[email protected]> wrote:
> > On Wed, 12 Jun 2013 13:39:18 +0530, Viresh Kumar wrote:
> >> On 12 June 2013 13:09, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> You don't have to add an extra "---" line. Just write your
> >> changelog after "---" added by git and give a blank line between
> >> your last changelog line and below ones (probably just to make it
> >> more readable and not a must, but i am not sure).
> >
> > I got your point. If you prefer, I will stick to it. No problem.
>
> Its not how I prefer it, but how everybody does it :)
Ok, :-)
>
> > As a side note:
> >
> > In the other open source project (u-boot) we use the pattern which
> > I've used previously. It has one big advantage - I can edit change
> > log at git gui (just below sign-of-by). It is simply more
> > convenient for me :-). Those changes between "---" are simply
> > skipped by git am afterwards.
>
> Yes, I am still asking you to follow the same steps:
>
> git send-email --annotate ***patches***
>
> and then write whatever you don't want to be logged by git am after
> the "---" already present in the patch.
Ok,
>
> >> >> > drivers/cpufreq/cpufreq.c | 69
> >> >> > ++++++++++++++++++++++++++++++++++++++++++
> >> >> > drivers/cpufreq/freq_table.c | 57
> >> >> > ++++++++++++++++++++++++++++++++--
> >> >> > include/linux/cpufreq.h | 12 ++++++++ 3 files changed,
> >> >> > 136 insertions(+), 2 deletions(-)
> >>
> >> > I think that we shall give users some flexibility and don't
> >> > assume that low_level_boost is only used for one solution/vendor.
> >> >
> >> > It is also needed with software controlled boost. Please refer to
> >> > patch 3/3.
> >>
> >> You didn't get me. I am not asking to keep it only for Intel. But
> >> keep this variable as is (s/low_level_boost/set_boost_freq), and
> >> make it optional. So, few drivers can implement it but not
> >> everybody is required to.
> >
> > The low_level_boost (set_boost_freq)[*] is optional. However it
> > seems to me, that the burden of changing available set of
> > frequencies (when boost is enabled) must be put to cpufreq driver
> > anyway.
>
> Driver shouldn't play with boost freqs at runtime. This has to be
> handled by cpufreq core. The only thing cpufreq driver must be doing
> in low_level_boost or set_boost_freq (as what I suggested it to be),
So you want the set_boost_freq to not be used with software based
boosting. Ok.
> is to set the boost frequency requested by core. And so this routine
> would only be defined by drivers that have a special way of setting
> boost frequencies. For others ->target() routine should be able to
> set all freqs, boost or non boost.
>
> > Without this function [*] defined, we cannot enable frequency
> > boosting.
>
> why?
Hmm, please read my further comment.
>
> >> So, Add another variable: boost_supported, which will tell cpufreq
> >> core that boost is supported by governor or not.
> > ^^^^^^^shouldn't it be cpufreq
> > driver?
>
> Yeah, sorry :(
Ok.
>
> > Ok, boost_supported seems needed. In my opinion it shall be defined
> > at cpufreq_driver structure (since it provides boosting
> > infrastructure anyway).
>
> that's what I asked.
Ok :-) .
>
> >> And a global variable in cpufreq.c boost_enabled to track status of
> >> what user has requested.
> >
> > I think, that boost_enable shall be also defined at cpufreq driver
> > (as proposed in the patch).
>
> Not really. Driver should only care about if it supports boost or not.
> If it is enabled/disabled by sysfs or not should be kept inside core
> in a global variable.
Ok,
>
> Moreover, if we have 5-6 cpufreq drivers compiled in (for multi-arch
> compiled kernels), we will save memory wasted by this variable if
> it is present in cpufreq_driver.
Ok. I didn't thought about this use case. Agree.
>
> > Moreover, boost_enable flag is already defined at
> > acpi-cpufreq.c (as static). We will have two flags for the same
> > purpose.
>
> No, we don't have to. Just expose another API from cpufreq core
> to get status of boost.
Ok.
>
> > So we want as follows:
> > show_boost = 1 ---> show only frequencies tagged as
> > CPUFREQ_BOOST_FREQ show_boost = 0 ---> show only "normal" (non
> > boost) frequencies
>
> Yes.
Ok,
>
> >> You are just talking about showing boost freqs in sysfs. I am
> >> talking about the frequencies that governors will select when
> >> boost is disabled from sysfs. Because we don't skip boost
> >> frequencies in target() routines, we will set them as and when
> >> governor requests them.
> >
> > I think, that it is the main issue here and it shall be cleared out:
> >
> > Frequencies marked as: CPUFREQ_BOOST_FREQ are added permanently to
> > the freq_table.
> > That is the distinction to the original overclocking patch posted
> > with
> >> LAB, where freq_boost structure was modified and boost frequencies
> >> were
> > either valid or invalid.
>
> Yes.
>
> > Then we can in SW control boost in two ways:
> > 1. change policy->max value (to the maximal boost frequency) - as
> > it is done now (v3) at Exynos. This is the simple solution (patch
> > 3/3)
>
> Drivers aren't supposed to set policy->max. It should be taken care
> of by core or freq_table.c file.
This seems the right thing, but it would require some functions defined
at freq_table.c to be extended to accept bool "boost" parameter (which
would not consider freqs tagged as CPUFREQ_BOOST_FREQ).
Then each per cpu policy, shall be read and its max freq shall be
updated when someone enables boost from sysfs (at
cpufreq_boost_trigger_state).
This is my idea to manage boost mode from core code. Am I right?
>
> > 2. Modify all freq_table helper functions to be aware of boost and
> > skip boost frequencies when boost_enable = 0. (as it was done at
> > v2). This requires code modification at freq_table.c and
> > reevaluation of policy.
>
> Yes, the core must be aware of it and must take the right decision
> here. So, we need to take care of boost freq in freq_table.c
Ok. Then we agreed :-).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally and disabled by default
The cpufreq_driver is responsibile for providing set_boost_freq callback
(if needed)
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- set_boost_freq - callback to function, which is necessary to
enable boost at the processor (like it is done at Intel)
- Boost sysfs attributies are seen only when cpufreq driver supports them.
They will not show up until either cpufreq_driver defines boost_supported
flag or device tree's cpufreq "boost_mode" attribute.
- No special spin_lock for Boost was created. The one from cpufreq_driver
was reused.
- The Boost code doesn't rely on any policy. When boost state is changed,
then policies attached to each CPU are updated.
Tested at: HW:
Exynos 4412 3.10 linux
Exynos 4210 3.10 linux
Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem) test
needed
Lukasz Majewski (3):
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
arch/arm/mach-s3c24xx/cpufreq.c | 2 +-
arch/powerpc/platforms/pasemi/cpufreq.c | 2 +-
arch/powerpc/platforms/powermac/cpufreq_32.c | 2 +-
arch/powerpc/platforms/powermac/cpufreq_64.c | 2 +-
drivers/cpufreq/acpi-cpufreq.c | 62 +++++++-----------
drivers/cpufreq/arm_big_little.c | 3 +-
drivers/cpufreq/blackfin-cpufreq.c | 2 +-
drivers/cpufreq/cpufreq-cpu0.c | 2 +-
drivers/cpufreq/cpufreq.c | 87 ++++++++++++++++++++++++++
drivers/cpufreq/cris-artpec3-cpufreq.c | 2 +-
drivers/cpufreq/cris-etraxfs-cpufreq.c | 2 +-
drivers/cpufreq/davinci-cpufreq.c | 2 +-
drivers/cpufreq/dbx500-cpufreq.c | 2 +-
drivers/cpufreq/e_powersaver.c | 3 +-
drivers/cpufreq/elanfreq.c | 2 +-
drivers/cpufreq/exynos-cpufreq.c | 7 ++-
drivers/cpufreq/exynos5440-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 44 ++++++++++---
drivers/cpufreq/ia64-acpi-cpufreq.c | 2 +-
drivers/cpufreq/imx6q-cpufreq.c | 2 +-
drivers/cpufreq/kirkwood-cpufreq.c | 3 +-
drivers/cpufreq/longhaul.c | 2 +-
drivers/cpufreq/loongson2_cpufreq.c | 2 +-
drivers/cpufreq/maple-cpufreq.c | 2 +-
drivers/cpufreq/omap-cpufreq.c | 2 +-
drivers/cpufreq/p4-clockmod.c | 2 +-
drivers/cpufreq/powernow-k6.c | 2 +-
drivers/cpufreq/powernow-k7.c | 2 +-
drivers/cpufreq/powernow-k8.c | 2 +-
drivers/cpufreq/ppc_cbe_cpufreq.c | 2 +-
drivers/cpufreq/pxa2xx-cpufreq.c | 4 +-
drivers/cpufreq/pxa3xx-cpufreq.c | 2 +-
drivers/cpufreq/s3c2416-cpufreq.c | 2 +-
drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
drivers/cpufreq/s5pv210-cpufreq.c | 2 +-
drivers/cpufreq/sc520_freq.c | 2 +-
drivers/cpufreq/sh-cpufreq.c | 2 +-
drivers/cpufreq/sparc-us2e-cpufreq.c | 2 +-
drivers/cpufreq/sparc-us3-cpufreq.c | 2 +-
drivers/cpufreq/spear-cpufreq.c | 3 +-
drivers/cpufreq/speedstep-centrino.c | 2 +-
drivers/cpufreq/speedstep-ich.c | 2 +-
drivers/cpufreq/speedstep-smi.c | 2 +-
drivers/cpufreq/tegra-cpufreq.c | 4 +-
include/linux/cpufreq.h | 18 +++++-
45 files changed, 211 insertions(+), 95 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software).
Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
its normal operation limits. Such a mode shall be only used for a short
time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) over clocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code.
By default boost is disabled. One global attribute is available at:
/sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with proper call to
sysfs.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
---
arch/arm/mach-s3c24xx/cpufreq.c | 2 +-
arch/powerpc/platforms/pasemi/cpufreq.c | 2 +-
arch/powerpc/platforms/powermac/cpufreq_32.c | 2 +-
arch/powerpc/platforms/powermac/cpufreq_64.c | 2 +-
drivers/cpufreq/acpi-cpufreq.c | 2 +-
drivers/cpufreq/arm_big_little.c | 3 +-
drivers/cpufreq/blackfin-cpufreq.c | 2 +-
drivers/cpufreq/cpufreq-cpu0.c | 2 +-
drivers/cpufreq/cpufreq.c | 87 ++++++++++++++++++++++++++
drivers/cpufreq/cris-artpec3-cpufreq.c | 2 +-
drivers/cpufreq/cris-etraxfs-cpufreq.c | 2 +-
drivers/cpufreq/davinci-cpufreq.c | 2 +-
drivers/cpufreq/dbx500-cpufreq.c | 2 +-
drivers/cpufreq/e_powersaver.c | 3 +-
drivers/cpufreq/elanfreq.c | 2 +-
drivers/cpufreq/exynos-cpufreq.c | 3 +-
drivers/cpufreq/exynos5440-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 44 ++++++++++---
drivers/cpufreq/ia64-acpi-cpufreq.c | 2 +-
drivers/cpufreq/imx6q-cpufreq.c | 2 +-
drivers/cpufreq/kirkwood-cpufreq.c | 3 +-
drivers/cpufreq/longhaul.c | 2 +-
drivers/cpufreq/loongson2_cpufreq.c | 2 +-
drivers/cpufreq/maple-cpufreq.c | 2 +-
drivers/cpufreq/omap-cpufreq.c | 2 +-
drivers/cpufreq/p4-clockmod.c | 2 +-
drivers/cpufreq/powernow-k6.c | 2 +-
drivers/cpufreq/powernow-k7.c | 2 +-
drivers/cpufreq/powernow-k8.c | 2 +-
drivers/cpufreq/ppc_cbe_cpufreq.c | 2 +-
drivers/cpufreq/pxa2xx-cpufreq.c | 4 +-
drivers/cpufreq/pxa3xx-cpufreq.c | 2 +-
drivers/cpufreq/s3c2416-cpufreq.c | 2 +-
drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
drivers/cpufreq/s5pv210-cpufreq.c | 2 +-
drivers/cpufreq/sc520_freq.c | 2 +-
drivers/cpufreq/sh-cpufreq.c | 2 +-
drivers/cpufreq/sparc-us2e-cpufreq.c | 2 +-
drivers/cpufreq/sparc-us3-cpufreq.c | 2 +-
drivers/cpufreq/spear-cpufreq.c | 3 +-
drivers/cpufreq/speedstep-centrino.c | 2 +-
drivers/cpufreq/speedstep-ich.c | 2 +-
drivers/cpufreq/speedstep-smi.c | 2 +-
drivers/cpufreq/tegra-cpufreq.c | 4 +-
include/linux/cpufreq.h | 18 +++++-
45 files changed, 187 insertions(+), 55 deletions(-)
diff --git a/arch/arm/mach-s3c24xx/cpufreq.c b/arch/arm/mach-s3c24xx/cpufreq.c
index 3c0e78e..882fcb5 100644
--- a/arch/arm/mach-s3c24xx/cpufreq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq.c
@@ -387,7 +387,7 @@ static int s3c_cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = cpu_cur.info->latency;
if (ftab)
- cpufreq_frequency_table_cpuinfo(policy, ftab);
+ cpufreq_frequency_table_cpuinfo(policy, ftab, 0);
return 0;
}
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
index be1e795..3d2fcc7 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -223,7 +223,7 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max
* are set correctly
*/
- return cpufreq_frequency_table_cpuinfo(policy, pas_freqs);
+ return cpufreq_frequency_table_cpuinfo(policy, pas_freqs, 0);
out_unmap_sdcpwr:
iounmap(sdcpwr_mapbase);
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 3104fad..f9805c6 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -408,7 +408,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cur = cur_freq;
cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
- return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
+ return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs, 0);
}
static u32 read_gpio(struct device_node *np)
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 7ba4234..cb7869b 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -365,7 +365,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
- g5_cpu_freqs);
+ g5_cpu_freqs, 0);
}
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 2845566..abca529 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -819,7 +819,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
perf->state = 0;
- result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table, 0);
if (result)
goto err_freqfree;
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 5d7f53f..f06567e 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -167,7 +167,8 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
if (ret)
return ret;
- ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]);
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster],
+ 0);
if (ret) {
dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
policy->cpu, cur_cluster);
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index 995511e80..65fc627 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -211,7 +211,7 @@ static int __bfin_cpu_init(struct cpufreq_policy *policy)
policy->cur = cclk;
cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu);
- return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table);
+ return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table, 0);
}
static struct freq_attr *bfin_freq_attr[] = {
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index ad1fde2..fd2f5f3 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -128,7 +128,7 @@ static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
{
int ret;
- ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (ret) {
pr_err("invalid frequency table: %d\n", ret);
return ret;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2ce86ed..02e57db 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -40,6 +40,7 @@
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver;
+static bool cpufreq_boost_enabled;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -315,6 +316,30 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %sable boost!\n", __func__,
+ enable ? "en" : "dis");
+ return -EINVAL;
+ }
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -1896,6 +1921,55 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+int cpufreq_boost_trigger_state(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+ int ret = 0, cpu;
+
+ if (!cpufreq_driver->boost_supported)
+ return -ENODEV;
+
+ if (cpufreq_boost_enabled != state) {
+ if (cpufreq_driver->set_boost_freq) {
+ ret = cpufreq_driver->set_boost_freq(state);
+ if (ret) {
+ pr_err("%s: BOOST cannot enable (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ for_each_possible_cpu(cpu) {
+ policy = cpufreq_cpu_get(cpu);
+ freq_table = cpufreq_frequency_get_table(cpu);
+ if (policy && freq_table) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_frequency_table_cpuinfo(policy,
+ freq_table,
+ state);
+ cpufreq_boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock,
+ flags);
+ }
+ }
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ state ? "enabled" : "disabled");
+
+ return 0;
+}
+
+int cpufreq_boost_state(void)
+{
+ return cpufreq_boost_enabled;
+}
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -1934,6 +2008,15 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_driver->boost_supported) {
+ ret = cpufreq_sysfs_create_file(&(boost.attr));
+ if (ret) {
+ pr_err("%s: cannot register global boost sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
goto err_null_driver;
@@ -1990,6 +2073,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+
+ if (cpufreq_driver->boost_supported)
+ cpufreq_sysfs_remove_file(&(boost.attr));
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags);
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index ee142c4..a50b6f5 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -82,7 +82,7 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = cris_freq_get_cpu_frequency(0);
- result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table, 0);
if (result)
return (result);
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index 1295223..3e09693 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -81,7 +81,7 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = cris_freq_get_cpu_frequency(0);
- result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table, 0);
if (result)
return (result);
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index c33c76c..e1ec64f 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -137,7 +137,7 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
policy->cur = davinci_getspeed(0);
- result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (result) {
pr_err("%s: cpufreq_frequency_table_cpuinfo() failed",
__func__);
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
index 6ec6539..30b89eb 100644
--- a/drivers/cpufreq/dbx500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -87,7 +87,7 @@ static int __cpuinit dbx500_cpufreq_init(struct cpufreq_policy *policy)
int res;
/* get policy fields based on the table */
- res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ res = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (!res)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 37380fb..1eea205 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -400,7 +400,8 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
policy->cur = fsb * current_multiplier;
- ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0]);
+ ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0],
+ 0);
if (ret) {
kfree(centaur);
return ret;
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index 658d860..6700524 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -223,7 +223,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = elanfreq_get_cpu_frequency(0);
- result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table, 0);
if (result)
return result;
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 3197d88..32ec2f6 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -253,7 +253,8 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpumask_setall(policy->cpus);
- return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+ return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table,
+ 0);
}
static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index 0c74018..936e239 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -323,7 +323,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
int ret;
- ret = cpufreq_frequency_table_cpuinfo(policy, dvfs_info->freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, dvfs_info->freq_table, 0);
if (ret) {
dev_err(dvfs_info->dev, "Invalid frequency table: %d\n", ret);
return ret;
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a7966..f1a4d785 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -21,7 +21,8 @@
*********************************************************************/
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table)
+ struct cpufreq_frequency_table *table,
+ int boost)
{
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
@@ -31,9 +32,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) {
pr_debug("table entry %u is invalid, skipping\n", i);
-
continue;
}
+ if (!boost && table[i].index == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u index\n",
i, freq, table[i].index);
if (freq < min_freq)
@@ -171,7 +174,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ int show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,22 +190,42 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ if (show_boost && table[i].index != CPUFREQ_BOOST_FREQ)
+ continue;
+ if (!show_boost && table[i].index == CPUFREQ_BOOST_FREQ)
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
return count;
-
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+/**
+ * show_scaling_available_frequencies - show normal boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 0);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 1);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index c0075db..7a29a92 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -335,7 +335,7 @@ acpi_cpufreq_cpu_init (
}
}
- result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table, 0);
if (result) {
goto err_freqfree;
}
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index b78bc35..9d09c29 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -172,7 +172,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
{
int ret;
- ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (ret) {
dev_err(cpu_dev, "invalid frequency table: %d\n", ret);
return ret;
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index b2644af..03b95bd 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -131,7 +131,8 @@ static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 5000; /* 5uS */
policy->cur = kirkwood_cpufreq_get_cpu_frequency(0);
- result = cpufreq_frequency_table_cpuinfo(policy, kirkwood_freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, kirkwood_freq_table,
+ 0);
if (result)
return result;
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index b448638..ef2cea3 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -921,7 +921,7 @@ static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 200000; /* nsec */
policy->cur = calc_speed(longhaul_get_cpu_mult());
- ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table, 0);
if (ret)
return ret;
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index d539127..fc8bcbb 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -136,7 +136,7 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
- &loongson2_clockmod_table[0]);
+ &loongson2_clockmod_table[0], 0);
}
static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index cdd6291..1b35285 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -184,7 +184,7 @@ static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(maple_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
- maple_cpu_freqs);
+ maple_cpu_freqs, 0);
}
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 0279d18..30473ae 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -191,7 +191,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
atomic_inc_return(&freq_table_users);
- result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (result)
goto fail_table;
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 421ef37..8f36e69 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -239,7 +239,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 10000001;
policy->cur = stock_freq;
- return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]);
+ return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0], 0);
}
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index ea0222a..4ffe7d5 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -167,7 +167,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 200000;
policy->cur = busfreq * max_multiplier;
- result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
+ result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio, 0);
if (result)
return result;
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 53888da..73c8345 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -683,7 +683,7 @@ static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
- return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
+ return cpufreq_frequency_table_cpuinfo(policy, powernow_table, 0);
}
static int powernow_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index b828efe..67d3283 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1156,7 +1156,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
pr_debug("policy current frequency %d kHz\n", pol->cur);
/* min/max the cpu is capable of */
- if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
+ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table), 0) {
printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table);
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index e577a1d..b50d9f1 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -127,7 +127,7 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* this ensures that policy->cpuinfo_min
* and policy->cpuinfo_max are set correctly */
- return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
+ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs, 0);
}
static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index 9e5bc8e..cd5d74a 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -453,10 +453,10 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
find_freq_tables(&pxa255_freq_table, &pxa255_freqs);
pr_info("PXA255 cpufreq using %s frequency table\n",
pxa255_turbo_table ? "turbo" : "run");
- cpufreq_frequency_table_cpuinfo(policy, pxa255_freq_table);
+ cpufreq_frequency_table_cpuinfo(policy, pxa255_freq_table, 0);
}
else if (cpu_is_pxa27x())
- cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table);
+ cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table, 0);
printk(KERN_INFO "PXA CPU frequency change support initialized\n");
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 15d60f8..c16d3f8 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -108,7 +108,7 @@ static int setup_freqs_table(struct cpufreq_policy *policy,
pxa3xx_freqs_num = num;
pxa3xx_freqs_table = table;
- return cpufreq_frequency_table_cpuinfo(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table, 0);
}
static void __update_core_freq(struct pxa3xx_freq_info *info)
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index 4f1881e..ea2b626 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -494,7 +494,7 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = (500 * 1000) +
s3c_freq->regulator_latency;
- ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table, 0);
if (ret)
goto err_freq_table;
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 27cacb5..137d29b 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -247,7 +247,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
*/
policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency;
- ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table, 0);
if (ret != 0) {
pr_err("Failed to configure frequency table: %d\n",
ret);
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 5c77570..8b7c790 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -557,7 +557,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 40000;
- return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
+ return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table, 0);
out_dmc1:
clk_put(dmc0_clk);
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index f740b13..d809fd0 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -117,7 +117,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = sc520_freq_get_cpu_frequency(0);
- result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table, 0);
if (result)
return result;
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 73adb64..c064d7c 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -120,7 +120,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (freq_table) {
int result;
- result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
if (!result)
cpufreq_frequency_table_get_attr(freq_table, cpu);
} else {
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 306ae46..c0345c4 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -324,7 +324,7 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
- return cpufreq_frequency_table_cpuinfo(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table, 0);
}
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index c71ee14..27a03b6 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -181,7 +181,7 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
- return cpufreq_frequency_table_cpuinfo(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table, 0);
}
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 156829f..517e19c 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -178,7 +178,8 @@ static int spear_cpufreq_init(struct cpufreq_policy *policy)
{
int ret;
- ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl);
+ ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl,
+ 0);
if (ret) {
pr_err("cpufreq_frequency_table_cpuinfo() failed");
return ret;
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 618e6f4..85b981b 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -403,7 +403,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur);
ret = cpufreq_frequency_table_cpuinfo(policy,
- per_cpu(centrino_model, policy->cpu)->op_points);
+ per_cpu(centrino_model, policy->cpu)->op_points, 0);
if (ret)
return (ret);
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index e2e5aa9..711c973 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -349,7 +349,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
/* cpuinfo and default policy values */
policy->cur = speed;
- result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
+ result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs, 0);
if (result)
return result;
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index f5a6b70..569e75e 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -329,7 +329,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = speed;
- result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
+ result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs, 0);
if (result)
return result;
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index c74c0e1..8bf95e0 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -216,7 +216,7 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
clk_prepare_enable(emc_clk);
clk_prepare_enable(cpu_clk);
- cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
policy->cur = tegra_getspeed(policy->cpu);
target_cpu_speed[policy->cpu] = policy->cur;
@@ -234,7 +234,7 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ cpufreq_frequency_table_cpuinfo(policy, freq_table, 0);
clk_disable_unprepare(emc_clk);
return 0;
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ab1932c..027442d 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -266,6 +266,10 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ int (*set_boost_freq) (int state);
};
/* flags */
@@ -318,6 +322,10 @@ __ATTR(_name, _perm, show_##_name, NULL)
static struct freq_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
struct global_attr {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj,
@@ -407,6 +415,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST_FREQ ~2
+
struct cpufreq_frequency_table {
unsigned int index; /* any */
unsigned int frequency; /* kHz - doesn't need to be in ascending
@@ -414,7 +425,8 @@ struct cpufreq_frequency_table {
};
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table);
+ struct cpufreq_frequency_table *table,
+ int boost);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
@@ -425,11 +437,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_state(void);
+
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The boost supported global flag was replaced with the one defined at acpi's
cpufreq driver.
The _store_boost() function has been redesigned to be used as set_boost_freq
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
---
drivers/cpufreq/acpi-cpufreq.c | 60 ++++++++++++++--------------------------
1 file changed, 20 insertions(+), 40 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index abca529..9cd528e 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,7 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
+static bool boost_enabled;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,20 +133,10 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
+ return 0;
get_online_cpus();
@@ -157,30 +147,31 @@ static ssize_t _store_boost(const char *buf, size_t count)
boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
+ return 0;
}
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_boost(const char *buf, size_t count)
{
- return _store_boost(buf, count);
-}
+ int ret;
+ unsigned long val = 0;
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
-}
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
+ _store_boost((int) val);
+
+ return count;
+}
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
@@ -930,8 +921,8 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
boost_enabled = boost_state(0);
+ acpi_cpufreq_driver.boost_supported = true;
get_online_cpus();
@@ -941,22 +932,11 @@ static void __init acpi_cpufreq_boost_init(void)
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
--
1.7.10.4
The struct cpufreq_driver has been extended to embrace the information
related to boost support.
When "boost_mode" device tree attribute is defined for a platform, the
boost_supported flag is set. Moreover boost related attributes were
exported.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
---
drivers/cpufreq/exynos-cpufreq.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 32ec2f6..0420d47 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -265,6 +265,7 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_scaling_boost_freqs,
NULL,
};
@@ -360,6 +361,7 @@ static struct of_device_id exynos_cpufreq_of_match[] __initconst = {
static int __init exynos_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -392,6 +394,8 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
}
locking_frequency = exynos_getspeed(0);
+ if (of_property_read_bool(node, "boost_mode"))
+ exynos_driver.boost_supported = 1;
register_pm_notifier(&exynos_cpufreq_nb);
--
1.7.10.4
On 14 June 2013 13:08, Lukasz Majewski <[email protected]> wrote:
> arch/arm/mach-s3c24xx/cpufreq.c | 2 +-
> arch/powerpc/platforms/pasemi/cpufreq.c | 2 +-
> arch/powerpc/platforms/powermac/cpufreq_32.c | 2 +-
> arch/powerpc/platforms/powermac/cpufreq_64.c | 2 +-
> drivers/cpufreq/acpi-cpufreq.c | 62 +++++++-----------
> drivers/cpufreq/arm_big_little.c | 3 +-
> drivers/cpufreq/blackfin-cpufreq.c | 2 +-
> drivers/cpufreq/cpufreq-cpu0.c | 2 +-
> drivers/cpufreq/cpufreq.c | 87 ++++++++++++++++++++++++++
> drivers/cpufreq/cris-artpec3-cpufreq.c | 2 +-
> drivers/cpufreq/cris-etraxfs-cpufreq.c | 2 +-
> drivers/cpufreq/davinci-cpufreq.c | 2 +-
> drivers/cpufreq/dbx500-cpufreq.c | 2 +-
> drivers/cpufreq/e_powersaver.c | 3 +-
> drivers/cpufreq/elanfreq.c | 2 +-
> drivers/cpufreq/exynos-cpufreq.c | 7 ++-
> drivers/cpufreq/exynos5440-cpufreq.c | 2 +-
> drivers/cpufreq/freq_table.c | 44 ++++++++++---
> drivers/cpufreq/ia64-acpi-cpufreq.c | 2 +-
> drivers/cpufreq/imx6q-cpufreq.c | 2 +-
> drivers/cpufreq/kirkwood-cpufreq.c | 3 +-
> drivers/cpufreq/longhaul.c | 2 +-
> drivers/cpufreq/loongson2_cpufreq.c | 2 +-
> drivers/cpufreq/maple-cpufreq.c | 2 +-
> drivers/cpufreq/omap-cpufreq.c | 2 +-
> drivers/cpufreq/p4-clockmod.c | 2 +-
> drivers/cpufreq/powernow-k6.c | 2 +-
> drivers/cpufreq/powernow-k7.c | 2 +-
> drivers/cpufreq/powernow-k8.c | 2 +-
> drivers/cpufreq/ppc_cbe_cpufreq.c | 2 +-
> drivers/cpufreq/pxa2xx-cpufreq.c | 4 +-
> drivers/cpufreq/pxa3xx-cpufreq.c | 2 +-
> drivers/cpufreq/s3c2416-cpufreq.c | 2 +-
> drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
> drivers/cpufreq/s5pv210-cpufreq.c | 2 +-
> drivers/cpufreq/sc520_freq.c | 2 +-
> drivers/cpufreq/sh-cpufreq.c | 2 +-
> drivers/cpufreq/sparc-us2e-cpufreq.c | 2 +-
> drivers/cpufreq/sparc-us3-cpufreq.c | 2 +-
> drivers/cpufreq/spear-cpufreq.c | 3 +-
> drivers/cpufreq/speedstep-centrino.c | 2 +-
> drivers/cpufreq/speedstep-ich.c | 2 +-
> drivers/cpufreq/speedstep-smi.c | 2 +-
> drivers/cpufreq/tegra-cpufreq.c | 4 +-
> include/linux/cpufreq.h | 18 +++++-
> 45 files changed, 211 insertions(+), 95 deletions(-)
Wow!! I am shocked to see these many files getting updated :)
On Mon, 17 Jun 2013 08:50:30 +0530, Viresh Kumar wrote:
> On 14 June 2013 13:08, Lukasz Majewski <[email protected]> wrote:
> > arch/arm/mach-s3c24xx/cpufreq.c | 2 +-
> > arch/powerpc/platforms/pasemi/cpufreq.c | 2 +-
> > arch/powerpc/platforms/powermac/cpufreq_32.c | 2 +-
> > arch/powerpc/platforms/powermac/cpufreq_64.c | 2 +-
> > drivers/cpufreq/acpi-cpufreq.c | 62
> > +++++++----------- drivers/cpufreq/arm_big_little.c
> > | 3 +- drivers/cpufreq/blackfin-cpufreq.c | 2 +-
> > drivers/cpufreq/cpufreq-cpu0.c | 2 +-
> > drivers/cpufreq/cpufreq.c | 87
> > ++++++++++++++++++++++++++
> > drivers/cpufreq/cris-artpec3-cpufreq.c | 2 +-
> > drivers/cpufreq/cris-etraxfs-cpufreq.c | 2 +-
> > drivers/cpufreq/davinci-cpufreq.c | 2 +-
> > drivers/cpufreq/dbx500-cpufreq.c | 2 +-
> > drivers/cpufreq/e_powersaver.c | 3 +-
> > drivers/cpufreq/elanfreq.c | 2 +-
> > drivers/cpufreq/exynos-cpufreq.c | 7 ++-
> > drivers/cpufreq/exynos5440-cpufreq.c | 2 +-
> > drivers/cpufreq/freq_table.c | 44 ++++++++++---
> > drivers/cpufreq/ia64-acpi-cpufreq.c | 2 +-
> > drivers/cpufreq/imx6q-cpufreq.c | 2 +-
> > drivers/cpufreq/kirkwood-cpufreq.c | 3 +-
> > drivers/cpufreq/longhaul.c | 2 +-
> > drivers/cpufreq/loongson2_cpufreq.c | 2 +-
> > drivers/cpufreq/maple-cpufreq.c | 2 +-
> > drivers/cpufreq/omap-cpufreq.c | 2 +-
> > drivers/cpufreq/p4-clockmod.c | 2 +-
> > drivers/cpufreq/powernow-k6.c | 2 +-
> > drivers/cpufreq/powernow-k7.c | 2 +-
> > drivers/cpufreq/powernow-k8.c | 2 +-
> > drivers/cpufreq/ppc_cbe_cpufreq.c | 2 +-
> > drivers/cpufreq/pxa2xx-cpufreq.c | 4 +-
> > drivers/cpufreq/pxa3xx-cpufreq.c | 2 +-
> > drivers/cpufreq/s3c2416-cpufreq.c | 2 +-
> > drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
> > drivers/cpufreq/s5pv210-cpufreq.c | 2 +-
> > drivers/cpufreq/sc520_freq.c | 2 +-
> > drivers/cpufreq/sh-cpufreq.c | 2 +-
> > drivers/cpufreq/sparc-us2e-cpufreq.c | 2 +-
> > drivers/cpufreq/sparc-us3-cpufreq.c | 2 +-
> > drivers/cpufreq/spear-cpufreq.c | 3 +-
> > drivers/cpufreq/speedstep-centrino.c | 2 +-
> > drivers/cpufreq/speedstep-ich.c | 2 +-
> > drivers/cpufreq/speedstep-smi.c | 2 +-
> > drivers/cpufreq/tegra-cpufreq.c | 4 +-
> > include/linux/cpufreq.h | 18 +++++- 45 files
> > changed, 211 insertions(+), 95 deletions(-)
>
> Wow!! I am shocked to see these many files getting updated :)
Hmm, CPUFREQ framework is quite popular :-).
Changing this one particular function, seemed to be the best solution.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 14 June 2013 13:08, Lukasz Majewski <[email protected]> wrote:
> Changes for v2:
> - Removal of cpufreq_boost structure and move its fields to cpufreq_driver
> structure
> - Flag to indicate if global boost attribute is already defined
> - Extent the pr_{err|debbug} functions to show current function names
>
> Changes for v3:
> - Method for reading boost status
> - Removal of cpufreq_frequency_table_max()
> - Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
> - boost_supported flag added to cpufreq_driver struct
> - "boost" sysfs attribute control flag removed
> - One global flag describing state of the boost defined at cpufreq core
> - Rename cpufreq_driver's low_level_boost field to set_boost_freq()
> - Usage of cpufreq_sysfs_{remove|add}_file() routines
Latest change log first please.
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 2ce86ed..02e57db 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -40,6 +40,7 @@
> * also protects the cpufreq_cpu_data array.
> */
> static struct cpufreq_driver *cpufreq_driver;
> +static bool cpufreq_boost_enabled;
> static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> #ifdef CONFIG_HOTPLUG_CPU
> /* This one keeps track of the previously set governor of a removed CPU */
> @@ -315,6 +316,30 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
> /*********************************************************************
> * SYSFS INTERFACE *
> *********************************************************************/
> +ssize_t show_boost(struct kobject *kobj,
> + struct attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%d\n", cpufreq_boost_enabled);
> +}
> +
> +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
> + const char *buf, size_t count)
> +{
> + int ret, enable;
> +
> + ret = sscanf(buf, "%d", &enable);
> + if (ret != 1 || enable < 0 || enable > 1)
> + return -EINVAL;
> +
> + if (cpufreq_boost_trigger_state(enable)) {
> + pr_err("%s: Cannot %sable boost!\n", __func__,
> + enable ? "en" : "dis");
Please don't use %sable as discussed earlier.
> + return -EINVAL;
> + }
> +
> + return count;
> +}
> +define_one_global_rw(boost);
>
> static struct cpufreq_governor *__find_governor(const char *str_governor)
> {
> @@ -1896,6 +1921,55 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
> };
>
> /*********************************************************************
> + * BOOST *
> + *********************************************************************/
> +int cpufreq_boost_trigger_state(int state)
> +{
> + struct cpufreq_frequency_table *freq_table;
> + struct cpufreq_policy *policy;
> + unsigned long flags;
> + int ret = 0, cpu;
> +
> + if (!cpufreq_driver->boost_supported)
> + return -ENODEV;
This can't happen. sysfs directory is present only when we
have boost supported.
> + if (cpufreq_boost_enabled != state) {
> + if (cpufreq_driver->set_boost_freq) {
> + ret = cpufreq_driver->set_boost_freq(state);
I thought this routine was for setting boost frequency and not
for enabling boost feature. If boost has to be enabled separately
then this routine must take care of it while setting freq.
So, in other words, this must not be called here.
> + if (ret) {
> + pr_err("%s: BOOST cannot enable (%d)\n",
> + __func__, ret);
> + return ret;
> + }
> + }
> +
> + for_each_possible_cpu(cpu) {
> + policy = cpufreq_cpu_get(cpu);
In case this code is required, it would make more sense to keep list
of all available policies, which we can iterate through.
> + freq_table = cpufreq_frequency_get_table(cpu);
> + if (policy && freq_table) {
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + cpufreq_frequency_table_cpuinfo(policy,
> + freq_table,
> + state);
We obviously don't need the last param to this routine and so bunch
of changes you did in this patch.
cpufreq_frequency_table_cpuinfo() can itself check if boost is enabled
or not.
> + cpufreq_boost_enabled = state;
> + write_unlock_irqrestore(&cpufreq_driver_lock,
> + flags);
> + }
> + }
I am not sure if this is required at all. Or what complications can be
there when we update max/min on the fly here.
> + }
> +
> + pr_debug("%s: cpufreq BOOST %s\n", __func__,
> + state ? "enabled" : "disabled");
> +
> + return 0;
> +}
> +
> +int cpufreq_boost_state(void)
s/cpufreq_boost_state/cpufreq_boost_enabled
> +{
> + return cpufreq_boost_enabled;
s/cpufreq_boost_enabled/boost_enabled
> +}
> +
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -1934,6 +2008,15 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + if (cpufreq_driver->boost_supported) {
> + ret = cpufreq_sysfs_create_file(&(boost.attr));
> + if (ret) {
> + pr_err("%s: cannot register global boost sysfs file\n",
> + __func__);
> + goto err_null_driver;
> + }
> + }
> +
> ret = subsys_interface_register(&cpufreq_interface);
> if (ret)
> goto err_null_driver;
> @@ -1990,6 +2073,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> pr_debug("unregistering driver %s\n", driver->name);
>
> subsys_interface_unregister(&cpufreq_interface);
> +
> + if (cpufreq_driver->boost_supported)
> + cpufreq_sysfs_remove_file(&(boost.attr));
> +
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> write_lock_irqsave(&cpufreq_driver_lock, flags);
This part looked good :)
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index d7a7966..f1a4d785 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -21,7 +21,8 @@
> *********************************************************************/
>
> int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
> - struct cpufreq_frequency_table *table)
> + struct cpufreq_frequency_table *table,
> + int boost)
> {
> unsigned int min_freq = ~0;
> unsigned int max_freq = 0;
> @@ -31,9 +32,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
> unsigned int freq = table[i].frequency;
> if (freq == CPUFREQ_ENTRY_INVALID) {
> pr_debug("table entry %u is invalid, skipping\n", i);
> -
> continue;
> }
> + if (!boost && table[i].index == CPUFREQ_BOOST_FREQ)
> + continue;
> +
> pr_debug("table entry %u: %u kHz, %u index\n",
> i, freq, table[i].index);
> if (freq < min_freq)
> @@ -171,7 +174,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
> /**
> * show_available_freqs - show available frequencies for the specified CPU
> */
> -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
> + int show_boost)
> {
> unsigned int i = 0;
> unsigned int cpu = policy->cpu;
> @@ -186,22 +190,42 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
> if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> continue;
> + if (show_boost && table[i].index != CPUFREQ_BOOST_FREQ)
> + continue;
> + if (!show_boost && table[i].index == CPUFREQ_BOOST_FREQ)
> + continue;
Maybe, this instead of above two if statements:
if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
continue
> count += sprintf(&buf[count], "%d ", table[i].frequency);
> }
> count += sprintf(&buf[count], "\n");
>
> return count;
> -
> }
>
> -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> - .attr = { .name = "scaling_available_frequencies",
> - .mode = 0444,
> - },
> - .show = show_available_freqs,
> -};
> +/**
> + * show_scaling_available_frequencies - show normal boost frequencies for
s/boost /
> + * the specified CPU
> + */
> +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 0);
> +}
> +cpufreq_attr_available_freq(scaling_available);
> EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
>
> +/**
> + * show_available_boost_freqs - show available boost frequencies for
> + * the specified CPU
> + */
> +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 1);
> +}
> +cpufreq_attr_available_freq(scaling_boost);
> +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> +
> /*
> * if you use these, you must assure that the frequency table is valid
> * all the time between get_attr and put_attr!
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index ab1932c..027442d 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -266,6 +266,10 @@ struct cpufreq_driver {
> int (*suspend) (struct cpufreq_policy *policy);
> int (*resume) (struct cpufreq_policy *policy);
> struct freq_attr **attr;
> +
> + /* platform specific boost support code */
> + bool boost_supported;
> + int (*set_boost_freq) (int state);
> };
>
> /* flags */
> @@ -318,6 +322,10 @@ __ATTR(_name, _perm, show_##_name, NULL)
> static struct freq_attr _name = \
> __ATTR(_name, 0644, show_##_name, store_##_name)
>
> +#define cpufreq_attr_available_freq(_name) \
> +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
> +__ATTR_RO(_name##_frequencies)
What is this doing in cpufreq.h? It will only be used by freq_table.c file.
Again, I couldn't see how boost freqs are getting used? You have
probably made them part of normal freq range here and so they
might be used during normal operations. But we wanted it to be
used only when we have few cpus on... etc.. Where is that logic?
On Mon, 17 Jun 2013 11:13:18 +0530, Viresh Kumar wrote:
> On 14 June 2013 13:08, Lukasz Majewski <[email protected]> wrote:
> > Changes for v2:
> > - Removal of cpufreq_boost structure and move its fields to
> > cpufreq_driver structure
> > - Flag to indicate if global boost attribute is already defined
> > - Extent the pr_{err|debbug} functions to show current function
> > names
> >
> > Changes for v3:
> > - Method for reading boost status
> > - Removal of cpufreq_frequency_table_max()
> > - Extent cpufreq_frequency_table_cpuinfo() to support boost
> > parameter
> > - boost_supported flag added to cpufreq_driver struct
> > - "boost" sysfs attribute control flag removed
> > - One global flag describing state of the boost defined at cpufreq
> > core
> > - Rename cpufreq_driver's low_level_boost field to set_boost_freq()
> > - Usage of cpufreq_sysfs_{remove|add}_file() routines
>
> Latest change log first please.
Ok.
>
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 2ce86ed..02e57db 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -40,6 +40,7 @@
> > * also protects the cpufreq_cpu_data array.
> > */
> > static struct cpufreq_driver *cpufreq_driver;
> > +static bool cpufreq_boost_enabled;
> > static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> > #ifdef CONFIG_HOTPLUG_CPU
> > /* This one keeps track of the previously set governor of a
> > removed CPU */ @@ -315,6 +316,30 @@
> > EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /*********************************************************************
> > * SYSFS
> > INTERFACE *
> > *********************************************************************/
> > +ssize_t show_boost(struct kobject *kobj,
> > + struct attribute *attr, char *buf)
> > +{
> > + return sprintf(buf, "%d\n", cpufreq_boost_enabled);
> > +}
> > +
> > +static ssize_t store_boost(struct kobject *kobj, struct attribute
> > *attr,
> > + const char *buf, size_t count)
> > +{
> > + int ret, enable;
> > +
> > + ret = sscanf(buf, "%d", &enable);
> > + if (ret != 1 || enable < 0 || enable > 1)
> > + return -EINVAL;
> > +
> > + if (cpufreq_boost_trigger_state(enable)) {
> > + pr_err("%s: Cannot %sable boost!\n", __func__,
> > + enable ? "en" : "dis");
>
> Please don't use %sable as discussed earlier.
My bad. I've overlooked this one.
>
> > + return -EINVAL;
> > + }
> > +
> > + return count;
> > +}
> > +define_one_global_rw(boost);
> >
> > static struct cpufreq_governor *__find_governor(const char
> > *str_governor) {
> > @@ -1896,6 +1921,55 @@ static struct notifier_block __refdata
> > cpufreq_cpu_notifier = { };
> >
> > /*********************************************************************
> > + *
> > BOOST *
> > +
> > *********************************************************************/
> > +int cpufreq_boost_trigger_state(int state) +{
> > + struct cpufreq_frequency_table *freq_table;
> > + struct cpufreq_policy *policy;
> > + unsigned long flags;
> > + int ret = 0, cpu;
> > +
> > + if (!cpufreq_driver->boost_supported)
> > + return -ENODEV;
>
> This can't happen. sysfs directory is present only when we
> have boost supported.
I know, that we shall not look into the future. But this method will be
used when somebody would like to enable boost from kernel. Let's say
new governor or such :-).
I can remove this and add it later, but I think, that it is safer to
add it straightaway.
>
> > + if (cpufreq_boost_enabled != state) {
> > + if (cpufreq_driver->set_boost_freq) {
> > + ret = cpufreq_driver->set_boost_freq(state);
>
> I thought this routine was for setting boost frequency and not
> for enabling boost feature. If boost has to be enabled separately
> then this routine must take care of it while setting freq.
>
> So, in other words, this must not be called here.
This function explicitly follows current logic of acpi-cpufreq.c.
I would like to avoid modifying legacy/working code as much as
possible (especially when I hadn't yet received any feedback about
acpi-cpufreq.c file changes).
>
> > + if (ret) {
> > + pr_err("%s: BOOST cannot enable
> > (%d)\n",
> > + __func__, ret);
> > + return ret;
> > + }
> > + }
> > +
> > + for_each_possible_cpu(cpu) {
> > + policy = cpufreq_cpu_get(cpu);
>
> In case this code is required, it would make more sense to keep list
> of all available policies, which we can iterate through.
Maybe I don't get the big picture, but why we cannot iterate
through possible CPUs? At least one shall have valid policy and
freq_table combination.
I've already proposed list of all policies (at v1), but we decided to
abandon this idea.
In which way list is better than iteration through all possible per-cpu
variables, which store policies?
>
> > + freq_table =
> > cpufreq_frequency_get_table(cpu);
> > + if (policy && freq_table) {
> > +
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > +
> > cpufreq_frequency_table_cpuinfo(policy,
> > +
> > freq_table,
> > +
> > state);
>
> We obviously don't need the last param to this routine and so bunch
> of changes you did in this patch.
>
> cpufreq_frequency_table_cpuinfo() can itself check if boost is enabled
> or not.
Yes, you are right. We can check if boost is supported and enabled
inside this function.
>
> > + cpufreq_boost_enabled = state;
> > +
> > write_unlock_irqrestore(&cpufreq_driver_lock,
> > + flags);
> > + }
> > + }
>
> I am not sure if this is required at all. Or what complications can be
> there when we update max/min on the fly here.
Correct me if I'm wrong, but I'm using scripts for tests which run
simultaneously and enables/disables boost feature. I don't recall if
there is a lock at sysfs, which would prevent from simultaneous write
to the "boost" sysfs attribute.
I will doubble check that.
>
> > + }
> > +
> > + pr_debug("%s: cpufreq BOOST %s\n", __func__,
> > + state ? "enabled" : "disabled");
> > +
> > + return 0;
> > +}
> > +
> > +int cpufreq_boost_state(void)
>
> s/cpufreq_boost_state/cpufreq_boost_enabled
OK.
>
> > +{
> > + return cpufreq_boost_enabled;
>
> s/cpufreq_boost_enabled/boost_enabled
>
> > +}
> > +
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -1934,6 +2008,15 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + if (cpufreq_driver->boost_supported) {
> > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> > + if (ret) {
> > + pr_err("%s: cannot register global boost
> > sysfs file\n",
> > + __func__);
> > + goto err_null_driver;
> > + }
> > + }
> > +
> > ret = subsys_interface_register(&cpufreq_interface);
> > if (ret)
> > goto err_null_driver;
> > @@ -1990,6 +2073,10 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> > subsys_interface_unregister(&cpufreq_interface);
> > +
> > + if (cpufreq_driver->boost_supported)
> > + cpufreq_sysfs_remove_file(&(boost.attr));
> > +
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
>
> This part looked good :)
>
> > diff --git a/drivers/cpufreq/freq_table.c
> > b/drivers/cpufreq/freq_table.c index d7a7966..f1a4d785 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -21,7 +21,8 @@
> > *********************************************************************/
> >
> > int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
> > - struct cpufreq_frequency_table
> > *table)
> > + struct cpufreq_frequency_table
> > *table,
> > + int boost)
> > {
> > unsigned int min_freq = ~0;
> > unsigned int max_freq = 0;
> > @@ -31,9 +32,11 @@ int cpufreq_frequency_table_cpuinfo(struct
> > cpufreq_policy *policy, unsigned int freq = table[i].frequency;
> > if (freq == CPUFREQ_ENTRY_INVALID) {
> > pr_debug("table entry %u is invalid,
> > skipping\n", i); -
> > continue;
> > }
> > + if (!boost && table[i].index == CPUFREQ_BOOST_FREQ)
> > + continue;
> > +
> > pr_debug("table entry %u: %u kHz, %u index\n",
> > i, freq, table[i].index);
> > if (freq < min_freq)
> > @@ -171,7 +174,8 @@ static DEFINE_PER_CPU(struct
> > cpufreq_frequency_table *, cpufreq_show_table); /**
> > * show_available_freqs - show available frequencies for the
> > specified CPU */
> > -static ssize_t show_available_freqs(struct cpufreq_policy *policy,
> > char *buf) +static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf,
> > + int show_boost)
> > {
> > unsigned int i = 0;
> > unsigned int cpu = policy->cpu;
> > @@ -186,22 +190,42 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf) for (i = 0;
> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
> > + if (show_boost && table[i].index !=
> > CPUFREQ_BOOST_FREQ)
> > + continue;
> > + if (!show_boost && table[i].index ==
> > CPUFREQ_BOOST_FREQ)
> > + continue;
>
> Maybe, this instead of above two if statements:
>
> if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
> continue
Yes. Good point.
>
> > count += sprintf(&buf[count], "%d ",
> > table[i].frequency); }
> > count += sprintf(&buf[count], "\n");
> >
> > return count;
> > -
> > }
> >
> > -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> > - .attr = { .name = "scaling_available_frequencies",
> > - .mode = 0444,
> > - },
> > - .show = show_available_freqs,
> > -};
> > +/**
> > + * show_scaling_available_frequencies - show normal boost
> > frequencies for
>
> s/boost /
Ok.
>
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_available_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 0);
> > +}
> > +cpufreq_attr_available_freq(scaling_available);
> > EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
> >
> > +/**
> > + * show_available_boost_freqs - show available boost frequencies
> > for
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_boost_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 1);
> > +}
> > +cpufreq_attr_available_freq(scaling_boost);
> > +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> > +
> > /*
> > * if you use these, you must assure that the frequency table is
> > valid
> > * all the time between get_attr and put_attr!
>
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index ab1932c..027442d 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -266,6 +266,10 @@ struct cpufreq_driver {
> > int (*suspend) (struct cpufreq_policy *policy);
> > int (*resume) (struct cpufreq_policy *policy);
> > struct freq_attr **attr;
> > +
> > + /* platform specific boost support code */
> > + bool boost_supported;
> > + int (*set_boost_freq) (int state);
> > };
> >
> > /* flags */
> > @@ -318,6 +322,10 @@ __ATTR(_name, _perm, show_##_name, NULL)
> > static struct freq_attr _name = \
> > __ATTR(_name, 0644, show_##_name, store_##_name)
> >
> > +#define cpufreq_attr_available_freq(_name) \
> > +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
> > +__ATTR_RO(_name##_frequencies)
>
> What is this doing in cpufreq.h? It will only be used by freq_table.c
> file.
I wanted to add those #defines to the place where other similar ones
are placed.
I can put it to freq_table.c.
>
>
> Again, I couldn't see how boost freqs are getting used? You have
> probably made them part of normal freq range here and so they
> might be used during normal operations. But we wanted it to be
> used only when we have few cpus on... etc.. Where is that logic?
The logic is as follow:
- cpufreq_driver exports .attr field. When driver supports boost then
two attributes are exported (even when boost is not enabled, but
supported):
- scaling_available_frequencies (only normal frequencies - this
attribute is unchanged)
- scaling_boost_frequencies - list possible boost frequencies.
When boost is not supported - then only scaling_available_frequencies
is exported (as it is done now).
Please refer to patch 3/3.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 June 2013 12:45, Lukasz Majewski <[email protected]> wrote:
> On Mon, 17 Jun 2013 11:13:18 +0530, Viresh Kumar wrote:
>> On 14 June 2013 13:08, Lukasz Majewski <[email protected]> wrote:
>> > +int cpufreq_boost_trigger_state(int state) +{
>> > + if (!cpufreq_driver->boost_supported)
>> > + return -ENODEV;
>>
>> This can't happen. sysfs directory is present only when we
>> have boost supported.
>
> I know, that we shall not look into the future. But this method will be
> used when somebody would like to enable boost from kernel. Let's say
> new governor or such :-).
We don't know if that would be acceptable or not as of now.
> I can remove this and add it later, but I think, that it is safer to
> add it straightaway.
Remove it for now.
>>
>> > + if (cpufreq_boost_enabled != state) {
>> > + if (cpufreq_driver->set_boost_freq) {
>> > + ret = cpufreq_driver->set_boost_freq(state);
>>
>> I thought this routine was for setting boost frequency and not
>> for enabling boost feature. If boost has to be enabled separately
>> then this routine must take care of it while setting freq.
>>
>> So, in other words, this must not be called here.
>
> This function explicitly follows current logic of acpi-cpufreq.c.
>
> I would like to avoid modifying legacy/working code as much as
> possible (especially when I hadn't yet received any feedback about
> acpi-cpufreq.c file changes).
Hmm.. I saw that code now. You are talking about: boost_set_msrs ??
So, this function has nothing to do with set_boost_freq() but
enable_boost(). Rename your function similarly and keep this code.
>> > + if (ret) {
>> > + pr_err("%s: BOOST cannot enable
>> > (%d)\n",
>> > + __func__, ret);
>> > + return ret;
>> > + }
>> > + }
>> > +
>> > + for_each_possible_cpu(cpu) {
>> > + policy = cpufreq_cpu_get(cpu);
>>
>> In case this code is required, it would make more sense to keep list
>> of all available policies, which we can iterate through.
>
> Maybe I don't get the big picture, but why we cannot iterate
> through possible CPUs? At least one shall have valid policy and
> freq_table combination.
Many cpus share same policy structure and so iterating over all of them
isn't a very good idea. Either keep a mask of cpus already iterated,
copy policy->cpus to it on each iteration. If a cpu is already done
skip loop for it.
OR keep a list of policies. I would prefer the later (do it in a separate
patch), as this can be used later too.
> I've already proposed list of all policies (at v1), but we decided to
> abandon this idea.
I don't remember why it was there but reason wasn't good enough to
keep it.
>> I am not sure if this is required at all. Or what complications can be
>> there when we update max/min on the fly here.
>
> Correct me if I'm wrong, but I'm using scripts for tests which run
> simultaneously and enables/disables boost feature. I don't recall if
> there is a lock at sysfs, which would prevent from simultaneous write
> to the "boost" sysfs attribute.
>
> I will doubble check that.
It isn't about a crash but how cpufreq subsystem works. I will think over
it later too, for now you can keep it.
>> > +{
>> > + return cpufreq_boost_enabled;
>>
>> s/cpufreq_boost_enabled/boost_enabled
??
>> > @@ -318,6 +322,10 @@ __ATTR(_name, _perm, show_##_name, NULL)
>> > static struct freq_attr _name = \
>> > __ATTR(_name, 0644, show_##_name, store_##_name)
>> >
>> > +#define cpufreq_attr_available_freq(_name) \
>> > +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
>> > +__ATTR_RO(_name##_frequencies)
>>
>> What is this doing in cpufreq.h? It will only be used by freq_table.c
>> file.
>
> I wanted to add those #defines to the place where other similar ones
> are placed.
That's not how these or any other declaration should be placed. By adding
these to cpufreq.h, you are inviting other parts of kernel to use them.
Which we don't want.
> I can put it to freq_table.c.
Thanks.
>> Again, I couldn't see how boost freqs are getting used? You have
>> probably made them part of normal freq range here and so they
>> might be used during normal operations. But we wanted it to be
>> used only when we have few cpus on... etc.. Where is that logic?
>
> The logic is as follow:
> - cpufreq_driver exports .attr field. When driver supports boost then
> two attributes are exported (even when boost is not enabled, but
> supported):
> - scaling_available_frequencies (only normal frequencies - this
> attribute is unchanged)
> - scaling_boost_frequencies - list possible boost frequencies.
>
> When boost is not supported - then only scaling_available_frequencies
> is exported (as it is done now).
You are missing the whole point behind keeping this patchset. Its not
about how to expose boost freqs to sysfs (that's what you are talking
about) but to use these frequencies on the fly. Some part of kernel
code would be setting these frequencies in real hardware. Who will
set these frequencies? On what basis? How do we ensure we don't
burn your chip?
On Mon, 17 Jun 2013 09:43:27 +0200, Viresh Kumar wrote:
> On 17 June 2013 12:45, Lukasz Majewski <[email protected]> wrote:
> > On Mon, 17 Jun 2013 11:13:18 +0530, Viresh Kumar wrote:
> >> On 14 June 2013 13:08, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > +int cpufreq_boost_trigger_state(int state) +{
>
> >> > + if (!cpufreq_driver->boost_supported)
> >> > + return -ENODEV;
> >>
> >> This can't happen. sysfs directory is present only when we
> >> have boost supported.
> >
> > I know, that we shall not look into the future. But this method
> > will be used when somebody would like to enable boost from kernel.
> > Let's say new governor or such :-).
>
> We don't know if that would be acceptable or not as of now.
>
> > I can remove this and add it later, but I think, that it is safer to
> > add it straightaway.
>
> Remove it for now.
Ok.
>
> >>
> >> > + if (cpufreq_boost_enabled != state) {
> >> > + if (cpufreq_driver->set_boost_freq) {
> >> > + ret =
> >> > cpufreq_driver->set_boost_freq(state);
> >>
> >> I thought this routine was for setting boost frequency and not
> >> for enabling boost feature. If boost has to be enabled separately
> >> then this routine must take care of it while setting freq.
> >>
> >> So, in other words, this must not be called here.
> >
> > This function explicitly follows current logic of acpi-cpufreq.c.
> >
> > I would like to avoid modifying legacy/working code as much as
> > possible (especially when I hadn't yet received any feedback about
> > acpi-cpufreq.c file changes).
>
> Hmm.. I saw that code now. You are talking about: boost_set_msrs ??
>
> So, this function has nothing to do with set_boost_freq() but
> enable_boost(). Rename your function similarly and keep this code.
Ok.
>
> >> > + if (ret) {
> >> > + pr_err("%s: BOOST cannot enable
> >> > (%d)\n",
> >> > + __func__, ret);
> >> > + return ret;
> >> > + }
> >> > + }
> >> > +
> >> > + for_each_possible_cpu(cpu) {
> >> > + policy = cpufreq_cpu_get(cpu);
> >>
> >> In case this code is required, it would make more sense to keep
> >> list of all available policies, which we can iterate through.
> >
> > Maybe I don't get the big picture, but why we cannot iterate
> > through possible CPUs? At least one shall have valid policy and
> > freq_table combination.
>
> Many cpus share same policy structure and so iterating over all of
> them isn't a very good idea. Either keep a mask of cpus already
> iterated, copy policy->cpus to it on each iteration. If a cpu is
> already done skip loop for it.
This is the situation, which I wanted to avoid. Policy has the
policy->cpus mask already implemented, but we don't know how/where to
hook to them (one solution would be to start from cpu0, but for some
reason I'm reluctant to do it in this way).
>
> OR keep a list of policies. I would prefer the later (do it in a
> separate patch), as this can be used later too.
I will declare a boost_policy list at cpufreq.c. Then I will add policy
to it, when cpufreq_add_dev() is called.
>
> > I've already proposed list of all policies (at v1), but we decided
> > to abandon this idea.
>
> I don't remember why it was there but reason wasn't good enough to
> keep it.
:-). Lets try with list.
>
> >> I am not sure if this is required at all. Or what complications
> >> can be there when we update max/min on the fly here.
> >
> > Correct me if I'm wrong, but I'm using scripts for tests which run
> > simultaneously and enables/disables boost feature. I don't recall if
> > there is a lock at sysfs, which would prevent from simultaneous
> > write to the "boost" sysfs attribute.
> >
> > I will doubble check that.
>
> It isn't about a crash but how cpufreq subsystem works. I will think
> over it later too, for now you can keep it.
OK.
>
> >> > +{
> >> > + return cpufreq_boost_enabled;
> >>
> >> s/cpufreq_boost_enabled/boost_enabled
>
> ??
I will change the name.
>
> >> > @@ -318,6 +322,10 @@ __ATTR(_name, _perm, show_##_name, NULL)
> >> > static struct freq_attr _name = \
> >> > __ATTR(_name, 0644, show_##_name, store_##_name)
> >> >
> >> > +#define cpufreq_attr_available_freq(_name) \
> >> > +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
> >> > +__ATTR_RO(_name##_frequencies)
> >>
> >> What is this doing in cpufreq.h? It will only be used by
> >> freq_table.c file.
> >
> > I wanted to add those #defines to the place where other similar ones
> > are placed.
>
> That's not how these or any other declaration should be placed. By
> adding these to cpufreq.h, you are inviting other parts of kernel to
> use them. Which we don't want.
>
> > I can put it to freq_table.c.
>
> Thanks.
Ok. I will keep the code local.
>
> >> Again, I couldn't see how boost freqs are getting used? You have
> >> probably made them part of normal freq range here and so they
> >> might be used during normal operations. But we wanted it to be
> >> used only when we have few cpus on... etc.. Where is that logic?
> >
> > The logic is as follow:
> > - cpufreq_driver exports .attr field. When driver supports boost
> > then two attributes are exported (even when boost is not enabled,
> > but supported):
> > - scaling_available_frequencies (only normal frequencies -
> > this attribute is unchanged)
> > - scaling_boost_frequencies - list possible boost
> > frequencies.
> >
> > When boost is not supported - then only
> > scaling_available_frequencies is exported (as it is done now).
>
> You are missing the whole point behind keeping this patchset. Its not
> about how to expose boost freqs to sysfs (that's what you are talking
> about) but to use these frequencies on the fly.
Two separate things:
1. I think, that scaling_available_frequencies [*] attribute has to
stay unchanged (this is how userspace sees the API). Linus would
we very unhappy :-) if we had changed public API.
x86 guys, please correct me, but I think that [*] will be not
changed (expanded) when Intel's HW boost is enabled at acpi-cpufreq.c
code.
The scaling_boost_frequencies is only visible when driver (and
probably soc maintainer) is ready to handle boosting. It shows over
clocked frequencies.
2. How we would control boost?
- To enable this you must mark IDs for some freqs as
CPUFREQ_BOOST_FREQ.
- The cpufreq_boost.boost_supported flag needs to be true (set at
cpufreq driver code)
- One needs to enable boosting by sysfs or call
cpufreq_boost_trigger_state(1); The latter will not work when
cpufreq_driver->boost_supported is not set.
I assume that when somebody takes those three above steps, then he is
aware that boost is working on his machine.
How one can control the boost? I'm now (on my setup) using thermal
subsystem. I set proper trip points and when one of them is met, then
boost is disabled. Moreover the thermal governor (stepwise) also
reduces frequency.
It works stable with v3.10 (with 3.8 there were some bugs - now they
are fixed).
The core acpi-cpufreq.c code hadn't been changed by me, so I assume
that it will work as before.
> Some part of kernel
> code would be setting these frequencies in real hardware. Who will
> set these frequencies?
Those freqs are set by ->target() callback (when allowed)
> On what basis? How do we ensure we don't
> burn your chip?
Thermal subsystem is a good example here. Another may be a
governor, or even scheduler.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 June 2013 14:38, Lukasz Majewski <[email protected]> wrote:
> On Mon, 17 Jun 2013 09:43:27 +0200, Viresh Kumar wrote:
>> Many cpus share same policy structure and so iterating over all of
>> them isn't a very good idea. Either keep a mask of cpus already
>> iterated, copy policy->cpus to it on each iteration. If a cpu is
>> already done skip loop for it.
>
> This is the situation, which I wanted to avoid. Policy has the
> policy->cpus mask already implemented, but we don't know how/where to
> hook to them (one solution would be to start from cpu0, but for some
> reason I'm reluctant to do it in this way).
We could have started from any cpu. Result and performance would have
been same.
>> OR keep a list of policies. I would prefer the later (do it in a
>> separate patch), as this can be used later too.
>
> I will declare a boost_policy list at cpufreq.c. Then I will add policy
> to it, when cpufreq_add_dev() is called.
This list doesn't have anything to do with boost. Its just a list of
all policies.
>> >> Again, I couldn't see how boost freqs are getting used? You have
>> >> probably made them part of normal freq range here and so they
>> >> might be used during normal operations. But we wanted it to be
>> >> used only when we have few cpus on... etc.. Where is that logic?
>> >
>> > The logic is as follow:
>> > - cpufreq_driver exports .attr field. When driver supports boost
>> > then two attributes are exported (even when boost is not enabled,
>> > but supported):
>> > - scaling_available_frequencies (only normal frequencies -
>> > this attribute is unchanged)
>> > - scaling_boost_frequencies - list possible boost
>> > frequencies.
>> >
>> > When boost is not supported - then only
>> > scaling_available_frequencies is exported (as it is done now).
>>
>> You are missing the whole point behind keeping this patchset. Its not
>> about how to expose boost freqs to sysfs (that's what you are talking
>> about) but to use these frequencies on the fly.
>
> Two separate things:
>
> 1. I think, that scaling_available_frequencies [*] attribute has to
> stay unchanged (this is how userspace sees the API). Linus would
> we very unhappy :-) if we had changed public API.
I never asked to modify it. :)
> x86 guys, please correct me, but I think that [*] will be not
> changed (expanded) when Intel's HW boost is enabled at acpi-cpufreq.c
> code.
>
> The scaling_boost_frequencies is only visible when driver (and
> probably soc maintainer) is ready to handle boosting. It shows over
> clocked frequencies.
Correct.
> 2. How we would control boost?
> - To enable this you must mark IDs for some freqs as
> CPUFREQ_BOOST_FREQ.
> - The cpufreq_boost.boost_supported flag needs to be true (set at
> cpufreq driver code)
> - One needs to enable boosting by sysfs or call
> cpufreq_boost_trigger_state(1); The latter will not work when
> cpufreq_driver->boost_supported is not set.
>
> I assume that when somebody takes those three above steps, then he is
> aware that boost is working on his machine.
All good until now.
> How one can control the boost? I'm now (on my setup) using thermal
> subsystem. I set proper trip points and when one of them is met, then
> boost is disabled. Moreover the thermal governor (stepwise) also
> reduces frequency.
>
> It works stable with v3.10 (with 3.8 there were some bugs - now they
> are fixed).
>
>
> The core acpi-cpufreq.c code hadn't been changed by me, so I assume
> that it will work as before.
That should adapt your patch in your patchset.
>> Some part of kernel
>> code would be setting these frequencies in real hardware. Who will
>> set these frequencies?
>
> Those freqs are set by ->target() callback (when allowed)
>From sysfs?? I thought we are going to have some automatic control
of this stuff from inside kernel. Userspace can't control when to run
on boost freqs.
>> On what basis? How do we ensure we don't
>> burn your chip?
>
> Thermal subsystem is a good example here. Another may be a
> governor, or even scheduler.
So, you are enabling boost from sysfs when your thermal framework
says, you can do it?
That's not going to work. There should be something inside kernel to
take care of this stuff. Otherwise a user may switch on boost accidentally
and may burn his chip.
On Mon, 17 Jun 2013 14:48:51 +0530, Viresh Kumar wrote:
> On 17 June 2013 14:38, Lukasz Majewski <[email protected]> wrote:
> > On Mon, 17 Jun 2013 09:43:27 +0200, Viresh Kumar wrote:
>
> >> Many cpus share same policy structure and so iterating over all of
> >> them isn't a very good idea. Either keep a mask of cpus already
> >> iterated, copy policy->cpus to it on each iteration. If a cpu is
> >> already done skip loop for it.
> >
> > This is the situation, which I wanted to avoid. Policy has the
> > policy->cpus mask already implemented, but we don't know how/where
> > to hook to them (one solution would be to start from cpu0, but for
> > some reason I'm reluctant to do it in this way).
>
> We could have started from any cpu. Result and performance would have
> been same.
Yes. But I don't want to hardcode anything. Especially starting CPU
number.
>
> >> OR keep a list of policies. I would prefer the later (do it in a
> >> separate patch), as this can be used later too.
> >
> > I will declare a boost_policy list at cpufreq.c. Then I will add
> > policy to it, when cpufreq_add_dev() is called.
>
> This list doesn't have anything to do with boost. Its just a list of
> all policies.
Ok, I see.
>
> >> >> Again, I couldn't see how boost freqs are getting used? You have
> >> >> probably made them part of normal freq range here and so they
> >> >> might be used during normal operations. But we wanted it to be
> >> >> used only when we have few cpus on... etc.. Where is that logic?
> >> >
> >> > The logic is as follow:
> >> > - cpufreq_driver exports .attr field. When driver supports boost
> >> > then two attributes are exported (even when boost is not enabled,
> >> > but supported):
> >> > - scaling_available_frequencies (only normal frequencies
> >> > - this attribute is unchanged)
> >> > - scaling_boost_frequencies - list possible boost
> >> > frequencies.
> >> >
> >> > When boost is not supported - then only
> >> > scaling_available_frequencies is exported (as it is done now).
> >>
> >> You are missing the whole point behind keeping this patchset. Its
> >> not about how to expose boost freqs to sysfs (that's what you are
> >> talking about) but to use these frequencies on the fly.
> >
> > Two separate things:
> >
> > 1. I think, that scaling_available_frequencies [*] attribute has to
> > stay unchanged (this is how userspace sees the API). Linus would
> > we very unhappy :-) if we had changed public API.
>
> I never asked to modify it. :)
:-)
>
> > x86 guys, please correct me, but I think that [*] will be not
> > changed (expanded) when Intel's HW boost is enabled at
> > acpi-cpufreq.c code.
> >
> > The scaling_boost_frequencies is only visible when driver (and
> > probably soc maintainer) is ready to handle boosting. It shows
> > over clocked frequencies.
>
> Correct.
Ok.
>
> > 2. How we would control boost?
> > - To enable this you must mark IDs for some freqs as
> > CPUFREQ_BOOST_FREQ.
> > - The cpufreq_boost.boost_supported flag needs to be true (set at
> > cpufreq driver code)
> > - One needs to enable boosting by sysfs or call
> > cpufreq_boost_trigger_state(1); The latter will not work when
> > cpufreq_driver->boost_supported is not set.
> >
> > I assume that when somebody takes those three above steps, then he
> > is aware that boost is working on his machine.
>
> All good until now.
Ok.
>
> > How one can control the boost? I'm now (on my setup) using thermal
> > subsystem. I set proper trip points and when one of them is met,
> > then boost is disabled. Moreover the thermal governor (stepwise)
> > also reduces frequency.
> >
> > It works stable with v3.10 (with 3.8 there were some bugs - now they
> > are fixed).
> >
> >
> > The core acpi-cpufreq.c code hadn't been changed by me, so I assume
> > that it will work as before.
>
> That should adapt your patch in your patchset.
>
> >> Some part of kernel
> >> code would be setting these frequencies in real hardware. Who will
> >> set these frequencies?
> >
> > Those freqs are set by ->target() callback (when allowed)
The ->target() [*] is called when governor calls it. I didn't change any
of this behaviour.
>
> From sysfs?? I thought we are going to have some automatic control
> of this stuff from inside kernel.
>From sysfs I just enable the boost. I do not order from userpace the
cpufreq to run with a particular (boosted) frequency.
When I enable boost - I ask (politely) the cpufreq core to reevaluate
policies and when applicable increase policy->max.
Then governor can use this new frequencies for normal operation.
> Userspace can't control when to run
> on boost freqs.
The control, if boost frequency shall be used or not, is done by
governor when load is appropriate.
>
> >> On what basis? How do we ensure we don't
> >> burn your chip?
> >
> > Thermal subsystem is a good example here. Another may be a
> > governor, or even scheduler.
>
> So, you are enabling boost from sysfs when your thermal framework
> says, you can do it?
No. I'm enabling boost from sysfs (modify policies). This does not mean
that boost frequency is run.
If governor decides, that it shall use boost freq - then it will use
it.
When during heavy workload (and running boost freq), the trip point for
thermal is being passed, the boost shall be disabled.
Moreover stepwise will also reduce frequency with which SoC runs.
>
> That's not going to work. There should be something inside kernel to
> take care of this stuff. Otherwise a user may switch on boost
> accidentally and may burn his chip.
User can by mistake enable boost. But then she/he needs to load SoC to
the maximum (to enable policy->max). After heating up the SoC - the
thermal goes in and disables boost and reduces frequency to cool down
the device.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 June 2013 15:28, Lukasz Majewski <[email protected]> wrote:
> Yes. But I don't want to hardcode anything. Especially starting CPU
> number.
There is nothing wrong with it. for_each_online_cpu() is good enough
on these cases.
>> > How one can control the boost? I'm now (on my setup) using thermal
>> > subsystem. I set proper trip points and when one of them is met,
>> > then boost is disabled. Moreover the thermal governor (stepwise)
>> > also reduces frequency.
>> >
>> > It works stable with v3.10 (with 3.8 there were some bugs - now they
>> > are fixed).
>> >
>> >
>> > The core acpi-cpufreq.c code hadn't been changed by me, so I assume
>> > that it will work as before.
>>
>> That should adapt your patch in your patchset.
??
>> From sysfs?? I thought we are going to have some automatic control
>> of this stuff from inside kernel.
>
> From sysfs I just enable the boost. I do not order from userpace the
> cpufreq to run with a particular (boosted) frequency.
>
> When I enable boost - I ask (politely) the cpufreq core to reevaluate
> policies and when applicable increase policy->max.
>
> Then governor can use this new frequencies for normal operation.
So, with your current patchset in, ondemand or conservative governors
will start using boost frequencies. Which might burn your chip.
On Mon, 17 Jun 2013 18:40:50 +0530, Viresh Kumar wrote:
> On 17 June 2013 15:28, Lukasz Majewski <[email protected]> wrote:
> > Yes. But I don't want to hardcode anything. Especially starting CPU
> > number.
>
> There is nothing wrong with it. for_each_online_cpu() is good enough
> on these cases.
I've already changed this code to use list of policies.
I will send this at v4.
>
> >> > How one can control the boost? I'm now (on my setup) using
> >> > thermal subsystem. I set proper trip points and when one of them
> >> > is met, then boost is disabled. Moreover the thermal governor
> >> > (stepwise) also reduces frequency.
> >> >
> >> > It works stable with v3.10 (with 3.8 there were some bugs - now
> >> > they are fixed).
> >> >
> >> >
> >> > The core acpi-cpufreq.c code hadn't been changed by me, so I
> >> > assume that it will work as before.
> >>
> >> That should adapt your patch in your patchset.
Could you explain what do you mean?
>
> ??
>
> >> From sysfs?? I thought we are going to have some automatic control
> >> of this stuff from inside kernel.
> >
> > From sysfs I just enable the boost. I do not order from userpace the
> > cpufreq to run with a particular (boosted) frequency.
> >
> > When I enable boost - I ask (politely) the cpufreq core to
> > reevaluate policies and when applicable increase policy->max.
> >
> > Then governor can use this new frequencies for normal operation.
>
> So, with your current patchset in, ondemand or conservative governors
> will start using boost frequencies. Which might burn your chip.
Two scenarios:
1. Thermal framework is compiled in and enabled (for exynos/other SoC)
-> trip point is reached -> boost is disabled -> frequency is reduced ->
SoC is cooled down.
I think, that thermal framework is a good "safe valve" here.
2. Thermal framework is disabled and user has enabled boost and used
ondemand / conservative governor.
Then execute gzip < /dev/urandom > /dev/null & (on all cores).
Then yes, chip will hang/burn due to crossing operating point (or burn).
What other means of control (despite of thermal) would you consider
applicable?
What comes to my mind is modifying governor logic to count how long the
CPU run with boost enabled and then disable it.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 June 2013 19:21, Lukasz Majewski <[email protected]> wrote:
> On Mon, 17 Jun 2013 18:40:50 +0530, Viresh Kumar wrote:
>> >> > The core acpi-cpufreq.c code hadn't been changed by me, so I
>> >> > assume that it will work as before.
>> >>
>> >> That should adapt your patch in your patchset.
>
> Could you explain what do you mean?
Update acpi-cpufreq to use your infrastructure.
>> >> From sysfs?? I thought we are going to have some automatic control
>> >> of this stuff from inside kernel.
>> >
>> > From sysfs I just enable the boost. I do not order from userpace the
>> > cpufreq to run with a particular (boosted) frequency.
>> >
>> > When I enable boost - I ask (politely) the cpufreq core to
>> > reevaluate policies and when applicable increase policy->max.
>> >
>> > Then governor can use this new frequencies for normal operation.
>>
>> So, with your current patchset in, ondemand or conservative governors
>> will start using boost frequencies. Which might burn your chip.
>
> Two scenarios:
> 1. Thermal framework is compiled in and enabled (for exynos/other SoC)
> -> trip point is reached -> boost is disabled -> frequency is reduced ->
> SoC is cooled down.
>
> I think, that thermal framework is a good "safe valve" here.
Even in this case boost shouldn't have been enabled by default.
Its not only about burning the chip but more than that.
According to my understanding, boost was important for power
saving. In case a high load can be managed by a single cpu with
boost freqs, then its better to use boost freqs rather than bringing
another cpu up.
Normally boost freqs are not so useful if we talk about powersaving,
as their energy consumption is much higher with not so great impact
on performance.
That's why when this thread started we talked about boost only when
one cpu is operational. But with your patch all cores can use boost
freq and thermal will come into picture just to save the chip.
That's wrong. This isn't why we invented boost here. Otherwise you
just don't need boost feature at all for your SoC. Just make these
freqs as available freqs and let thermal control policy->max/min
to save your chip.
> 2. Thermal framework is disabled and user has enabled boost and used
> ondemand / conservative governor.
> Then execute gzip < /dev/urandom > /dev/null & (on all cores).
>
> Then yes, chip will hang/burn due to crossing operating point (or burn).
>
>
> What other means of control (despite of thermal) would you consider
> applicable?
>
> What comes to my mind is modifying governor logic to count how long the
> CPU run with boost enabled and then disable it.
Its not about how long.. One cpu type can work longer with boost freq
compared to other.
What we probably need is:
- Enabled boost from sysfs if required (now below steps will come into
picture)
- See how many cpus are running, if only one then start using boost freqs
- Now thermal should be come into picture to save chip in case a single
cpu running at boost can burn it out.
On Tue, 18 Jun 2013 08:42:13 +0200, Viresh Kumar wrote:
> On 17 June 2013 19:21, Lukasz Majewski <[email protected]> wrote:
> > On Mon, 17 Jun 2013 18:40:50 +0530, Viresh Kumar wrote:
> >> >> > The core acpi-cpufreq.c code hadn't been changed by me, so I
> >> >> > assume that it will work as before.
> >> >>
> >> >> That should adapt your patch in your patchset.
> >
> > Could you explain what do you mean?
>
> Update acpi-cpufreq to use your infrastructure.
Ach... It is already done, since I always post acpi related patch to
the boost series :-).
>
> >> >> From sysfs?? I thought we are going to have some automatic
> >> >> control of this stuff from inside kernel.
> >> >
> >> > From sysfs I just enable the boost. I do not order from userpace
> >> > the cpufreq to run with a particular (boosted) frequency.
> >> >
> >> > When I enable boost - I ask (politely) the cpufreq core to
> >> > reevaluate policies and when applicable increase policy->max.
> >> >
> >> > Then governor can use this new frequencies for normal operation.
> >>
> >> So, with your current patchset in, ondemand or conservative
> >> governors will start using boost frequencies. Which might burn
> >> your chip.
> >
> > Two scenarios:
> > 1. Thermal framework is compiled in and enabled (for exynos/other
> > SoC) -> trip point is reached -> boost is disabled -> frequency is
> > reduced -> SoC is cooled down.
> >
> > I think, that thermal framework is a good "safe valve" here.
>
> Even in this case boost shouldn't have been enabled by default.
> Its not only about burning the chip but more than that.
>
> According to my understanding, boost was important for power
> saving. In case a high load can be managed by a single cpu with
> boost freqs, then its better to use boost freqs rather than bringing
> another cpu up.
>
> Normally boost freqs are not so useful if we talk about powersaving,
> as their energy consumption is much higher with not so great impact
> on performance.
>
> That's why when this thread started we talked about boost only when
> one cpu is operational. But with your patch all cores can use boost
> freq and thermal will come into picture just to save the chip.
I agree here.
>
> That's wrong. This isn't why we invented boost here. Otherwise you
> just don't need boost feature at all for your SoC. Just make these
> freqs as available freqs and let thermal control policy->max/min
> to save your chip.
Also I agree.
>
> > 2. Thermal framework is disabled and user has enabled boost and used
> > ondemand / conservative governor.
> > Then execute gzip < /dev/urandom > /dev/null & (on all cores).
> >
> > Then yes, chip will hang/burn due to crossing operating point (or
> > burn).
> >
> >
> > What other means of control (despite of thermal) would you consider
> > applicable?
> >
> > What comes to my mind is modifying governor logic to count how long
> > the CPU run with boost enabled and then disable it.
>
> Its not about how long.. One cpu type can work longer with boost freq
> compared to other.
>
> What we probably need is:
> - Enabled boost from sysfs if required (now below steps will come into
> picture)
> - See how many cpus are running, if only one then start using boost
> freqs
You are right here.
I'd like to propose following solution:
1. For acpi (where boost_enable come into play) - do not consider
number of active cpus (this is done in HW anyway)
2. For SW solution evaluate how many CPUs are running. If only one is
running then allow enabling boost from sysfs.
But following situation is also possible: User enable boost when one
core is only running and then for some reason other core is woken up.
What shall be done then?
Shall we then disable boost immediately when cpufreq detects that
more than one core is running? Or leave this situation to be handled by
thermal subsystem?
As a side note:
Logic proposed at point 2, is already implemented at LAB
(enable LAB only when one core is running and disable it when more
than one come into play).
> - Now thermal should be come into picture to save chip in case a
> single cpu running at boost can burn it out.
I will extent v4 to embrace code which switches off boost at thermal.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 18 June 2013 13:54, Lukasz Majewski <[email protected]> wrote:
> On Tue, 18 Jun 2013 08:42:13 +0200, Viresh Kumar wrote:
>> Its not about how long.. One cpu type can work longer with boost freq
>> compared to other.
>>
>> What we probably need is:
>> - Enabled boost from sysfs if required (now below steps will come into
>> picture)
>> - See how many cpus are running, if only one then start using boost
>> freqs
>
> You are right here.
>
> I'd like to propose following solution:
> 1. For acpi (where boost_enable come into play) - do not consider
> number of active cpus (this is done in HW anyway)
>
> 2. For SW solution evaluate how many CPUs are running. If only one is
> running then allow enabling boost from sysfs.
Looks fine.
> But following situation is also possible: User enable boost when one
> core is only running and then for some reason other core is woken up.
> What shall be done then?
> Shall we then disable boost immediately when cpufreq detects that
> more than one core is running? Or leave this situation to be handled by
> thermal subsystem?
Obviously disable boost ASAP. Every SoC might not have a thermal
framework glue to do it.
> As a side note:
> Logic proposed at point 2, is already implemented at LAB
> (enable LAB only when one core is running and disable it when more
> than one come into play).
Hmm.. So, eventually that will go away now :)
>> - Now thermal should be come into picture to save chip in case a
>> single cpu running at boost can burn it out.
>
> I will extent v4 to embrace code which switches off boost at thermal.
Gud.
On Tue, 18 Jun 2013 14:10:28 +0530, Viresh Kumar wrote:
> On 18 June 2013 13:54, Lukasz Majewski <[email protected]> wrote:
> > On Tue, 18 Jun 2013 08:42:13 +0200, Viresh Kumar wrote:
>
> >> Its not about how long.. One cpu type can work longer with boost
> >> freq compared to other.
> >>
> >> What we probably need is:
> >> - Enabled boost from sysfs if required (now below steps will come
> >> into picture)
> >> - See how many cpus are running, if only one then start using boost
> >> freqs
> >
> > You are right here.
> >
> > I'd like to propose following solution:
> > 1. For acpi (where boost_enable come into play) - do not consider
> > number of active cpus (this is done in HW anyway)
> >
> > 2. For SW solution evaluate how many CPUs are running. If only one
> > is running then allow enabling boost from sysfs.
>
> Looks fine.
Ok,
>
> > But following situation is also possible: User enable boost when one
> > core is only running and then for some reason other core is woken
> > up. What shall be done then?
> > Shall we then disable boost immediately when cpufreq detects that
> > more than one core is running? Or leave this situation to be
> > handled by thermal subsystem?
>
> Obviously disable boost ASAP. Every SoC might not have a thermal
> framework glue to do it.
Implementation of counting number of idle CPUs would impose extending
the cpufreq core itself. Do you have any hints how this can be done in
a neat way?
I suspect, that porting the LAB solution to the cpufreq core may be not
easy. I think that the best place for it would be governor core code.
>
> > As a side note:
> > Logic proposed at point 2, is already implemented at LAB
> > (enable LAB only when one core is running and disable it when more
> > than one come into play).
>
> Hmm.. So, eventually that will go away now :)
But this is not the only functionality, which LAB posses :-).
>
> >> - Now thermal should be come into picture to save chip in case a
> >> single cpu running at boost can burn it out.
> >
> > I will extent v4 to embrace code which switches off boost at
> > thermal.
>
> Gud.
Ok.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tuesday, June 18, 2013 12:12:13 PM Viresh Kumar wrote:
> On 17 June 2013 19:21, Lukasz Majewski <[email protected]> wrote:
> > On Mon, 17 Jun 2013 18:40:50 +0530, Viresh Kumar wrote:
> >> >> > The core acpi-cpufreq.c code hadn't been changed by me, so I
> >> >> > assume that it will work as before.
> >> >>
> >> >> That should adapt your patch in your patchset.
> >
> > Could you explain what do you mean?
>
> Update acpi-cpufreq to use your infrastructure.
>
> >> >> From sysfs?? I thought we are going to have some automatic control
> >> >> of this stuff from inside kernel.
> >> >
> >> > From sysfs I just enable the boost. I do not order from userpace the
> >> > cpufreq to run with a particular (boosted) frequency.
> >> >
> >> > When I enable boost - I ask (politely) the cpufreq core to
> >> > reevaluate policies and when applicable increase policy->max.
> >> >
> >> > Then governor can use this new frequencies for normal operation.
> >>
> >> So, with your current patchset in, ondemand or conservative governors
> >> will start using boost frequencies. Which might burn your chip.
> >
> > Two scenarios:
> > 1. Thermal framework is compiled in and enabled (for exynos/other SoC)
> > -> trip point is reached -> boost is disabled -> frequency is reduced ->
> > SoC is cooled down.
> >
> > I think, that thermal framework is a good "safe valve" here.
>
> Even in this case boost shouldn't have been enabled by default.
> Its not only about burning the chip but more than that.
>
> According to my understanding, boost was important for power
> saving. In case a high load can be managed by a single cpu with
> boost freqs, then its better to use boost freqs rather than bringing
> another cpu up.
Do you mean the 'boost' sysfs attribute or the 'turbo frequencies' concept?
> Normally boost freqs are not so useful if we talk about powersaving,
> as their energy consumption is much higher with not so great impact
> on performance.
Er, er, please be careful here. The impact on performance may be sufficient
for deep C-states to become relevant in some cases.
> That's why when this thread started we talked about boost only when
> one cpu is operational. But with your patch all cores can use boost
> freq and thermal will come into picture just to save the chip.
Well, that's why on x86 turbo is controlled by hardware that takes care of
keeping things within the chip's thermal limits.
> That's wrong. This isn't why we invented boost here. Otherwise you
> just don't need boost feature at all for your SoC. Just make these
> freqs as available freqs and let thermal control policy->max/min
> to save your chip.
The 'boost' attribute added by acpi-cpufreq means "let the hardware use turbo
frequencies".
I'd recommend you both to read Documentation/cpu-freq/boost.txt now. :-)
I think we can extend the meaning to "let turbo frequencies be used", but if
we need software to play the role of the hardware's thermal control, we need
to be very careful.
> > 2. Thermal framework is disabled and user has enabled boost and used
> > ondemand / conservative governor.
> > Then execute gzip < /dev/urandom > /dev/null & (on all cores).
> >
> > Then yes, chip will hang/burn due to crossing operating point (or burn).
> >
> >
> > What other means of control (despite of thermal) would you consider
> > applicable?
> >
> > What comes to my mind is modifying governor logic to count how long the
> > CPU run with boost enabled and then disable it.
>
> Its not about how long.. One cpu type can work longer with boost freq
> compared to other.
>
> What we probably need is:
> - Enabled boost from sysfs if required (now below steps will come into
> picture)
This has to be compatible with the existing stuff.
> - See how many cpus are running, if only one then start using boost freqs
> - Now thermal should be come into picture to save chip in case a single
> cpu running at boost can burn it out.
I'd say there needs to be a separate controller/monitor for that that will
know what the chip's thermal limit is and how that relates to how fast the
CPU core(s) may run and for how much time. I'm not sure it is sufficient
to "wait for thermal to kick in" here, because you may need to slow down
things in advance (i.e. before thermal sensors tell you there's too much heat,
because that may be too late already).
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Tue, 18 Jun 2013 15:26:16 +0200, Rafael J. Wysocki wrote:
> On Tuesday, June 18, 2013 12:12:13 PM Viresh Kumar wrote:
> > On 17 June 2013 19:21, Lukasz Majewski <[email protected]>
> > wrote:
> > > On Mon, 17 Jun 2013 18:40:50 +0530, Viresh Kumar wrote:
> > >> >> > The core acpi-cpufreq.c code hadn't been changed by me, so I
> > >> >> > assume that it will work as before.
> > >> >>
> > >> >> That should adapt your patch in your patchset.
> > >
> > > Could you explain what do you mean?
> >
> > Update acpi-cpufreq to use your infrastructure.
> >
> > >> >> From sysfs?? I thought we are going to have some automatic
> > >> >> control of this stuff from inside kernel.
> > >> >
> > >> > From sysfs I just enable the boost. I do not order from
> > >> > userpace the cpufreq to run with a particular (boosted)
> > >> > frequency.
> > >> >
> > >> > When I enable boost - I ask (politely) the cpufreq core to
> > >> > reevaluate policies and when applicable increase policy->max.
> > >> >
> > >> > Then governor can use this new frequencies for normal
> > >> > operation.
> > >>
> > >> So, with your current patchset in, ondemand or conservative
> > >> governors will start using boost frequencies. Which might burn
> > >> your chip.
> > >
> > > Two scenarios:
> > > 1. Thermal framework is compiled in and enabled (for exynos/other
> > > SoC) -> trip point is reached -> boost is disabled -> frequency
> > > is reduced -> SoC is cooled down.
> > >
> > > I think, that thermal framework is a good "safe valve" here.
> >
> > Even in this case boost shouldn't have been enabled by default.
> > Its not only about burning the chip but more than that.
> >
> > According to my understanding, boost was important for power
> > saving. In case a high load can be managed by a single cpu with
> > boost freqs, then its better to use boost freqs rather than bringing
> > another cpu up.
>
> Do you mean the 'boost' sysfs attribute or the 'turbo frequencies'
> concept?
>
> > Normally boost freqs are not so useful if we talk about powersaving,
> > as their energy consumption is much higher with not so great impact
> > on performance.
>
> Er, er, please be careful here. The impact on performance may be
> sufficient for deep C-states to become relevant in some cases.
>
> > That's why when this thread started we talked about boost only when
> > one cpu is operational. But with your patch all cores can use boost
> > freq and thermal will come into picture just to save the chip.
>
> Well, that's why on x86 turbo is controlled by hardware that takes
> care of keeping things within the chip's thermal limits.
And this is the reason why I don't want to overly change acpi-cpufreq.c
code. :-)
>
> > That's wrong. This isn't why we invented boost here. Otherwise you
> > just don't need boost feature at all for your SoC. Just make these
> > freqs as available freqs and let thermal control policy->max/min
> > to save your chip.
>
> The 'boost' attribute added by acpi-cpufreq means "let the hardware
> use turbo frequencies".
This is HW managed. We only enable the switch and then simply forget
about it.
>
> I'd recommend you both to read Documentation/cpu-freq/boost.txt
> now. :-)
According to the documentation:
"Reading the file is always supported, even if the processor does not
support boosting. In this case the file will be read-only and always
reads as "0""
Hmm, in the proposed patch set, the "boost" attribute is only exported
when cpufreq driver sets boost_supported flag.
>
> I think we can extend the meaning to "let turbo frequencies be used",
> but if we need software to play the role of the hardware's thermal
> control, we need to be very careful.
>
> > > 2. Thermal framework is disabled and user has enabled boost and
> > > used ondemand / conservative governor.
> > > Then execute gzip < /dev/urandom > /dev/null & (on all cores).
> > >
> > > Then yes, chip will hang/burn due to crossing operating point (or
> > > burn).
> > >
> > >
> > > What other means of control (despite of thermal) would you
> > > consider applicable?
> > >
> > > What comes to my mind is modifying governor logic to count how
> > > long the CPU run with boost enabled and then disable it.
> >
> > Its not about how long.. One cpu type can work longer with boost
> > freq compared to other.
> >
> > What we probably need is:
> > - Enabled boost from sysfs if required (now below steps will come
> > into picture)
>
> This has to be compatible with the existing stuff.
>
> > - See how many cpus are running, if only one then start using boost
> > freqs
> > - Now thermal should be come into picture to save chip in case a
> > single cpu running at boost can burn it out.
>
> I'd say there needs to be a separate controller/monitor for that that
> will know what the chip's thermal limit is and how that relates to
> how fast the CPU core(s) may run and for how much time. I'm not sure
> it is sufficient to "wait for thermal to kick in" here, because you
> may need to slow down things in advance (i.e. before thermal sensors
> tell you there's too much heat, because that may be too late already).
I think that thermal subsystem shall be the second option to disable SW
boosting.
The main control shall be done inside the cpufreq core. The idea to
disable boost when more than one core is active is rational.
I'm going to implement this concept at v4.
>
> Thanks,
> Rafael
>
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tue, 18 Jun 2013 15:44:56 +0200, Lukasz Majewski wrote:
Dear Viesh, Rafael,
> >
> > I'd recommend you both to read Documentation/cpu-freq/boost.txt
> > now. :-)
>
>
> According to the documentation:
> "Reading the file is always supported, even if the processor does not
> support boosting. In this case the file will be read-only and always
> reads as "0""
>
> Hmm, in the proposed patch set, the "boost" attribute is only exported
> when cpufreq driver sets boost_supported flag.
I would like to clarify the above issue.
When I've discussed with Viresh previous version of this patch, we have
agreed, that "boost" sysfs attribute [*]:
/sys/devices/system/cpu/cpufreq/boost
would be only visible when boost_supported flag is set at cpufreq
driver.
When acpi-cpufreq driver doesn't support boost, the attribute [*]
won't be exported at all. This contradicts the documentation and legacy
acpi-cpufreq behaviour.
Since I'm affraid to break API (with all its consequences :-) ), I would
like to be sure that this is OK, and thereof I'm allowed to rewrite
documentation accordingly.
I simply need explicit permission from both maintainers :-).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally and disabled by default
The cpufreq_driver is responsibile for setting boost_supported flag and
providing enable_boost callback(if HW support is needed)
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- enable_boost - callback to function, which is necessary to
enable boost in the processor (like it is done at Intel)
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is always
provided.
It will be read only, until either cpufreq_driver defines boost_supported
flag or device tree's cpufreq "boost_mode" attribute is defined. It is
consistent with legacy acpi API.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- All available policies are now stored in a list.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- Number of busy cpus (with load > 90%) is calculated and exported as a
global sysfs attribute.
- The SW based boost can be only enabled when up to one core is regarded as
a "busy" one. For safety reasons boost is disabled when more cores comes
into play.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached.
New patches for v4:
cpufreq: Store cpufreq policies in a list
cpufreq: Calculate number of busy CPUs
cpufreq: Enable software boost only when up to one busy core is running
thermal:boost: Disable boost when trip point is reached
Tested at: HW:
Exynos 4412 3.10 linux
Exynos 4210 3.10 linux
Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem) test
needed
Lukasz Majewski (7):
cpufreq: Store cpufreq policies in a list
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
cpufreq: Calculate number of busy CPUs
cpufreq: Enable software boost only when up to one busy core is
running
thermal:boost: Disable boost when trip point is reached
drivers/cpufreq/acpi-cpufreq.c | 61 ++++++-----------
drivers/cpufreq/cpufreq.c | 132 ++++++++++++++++++++++++++++++++++++
drivers/cpufreq/cpufreq_governor.c | 4 ++
drivers/cpufreq/exynos-cpufreq.c | 4 ++
drivers/cpufreq/freq_table.c | 43 ++++++++++--
drivers/thermal/cpu_cooling.c | 3 +
include/linux/cpufreq.h | 15 ++++
7 files changed, 215 insertions(+), 47 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software).
Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
its normal operation limits. Such a mode shall be only used for a short
time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) over clocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code.
Boost sysfs attribute is always exported (to support legacy API). By
default boost is exported as read only. One global attribute is available at:
/sys/devices/system/cpu/cpufreq/boost.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with proper call to
sysfs.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock
- Always export boost attribute (preserve legacy behaviour). When boost
is not supported this attribute is read only
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
---
drivers/cpufreq/cpufreq.c | 95 ++++++++++++++++++++++++++++++++++++++++++
drivers/cpufreq/freq_table.c | 43 +++++++++++++++----
include/linux/cpufreq.h | 11 +++++
3 files changed, 142 insertions(+), 7 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 665e641..9141d33 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -40,6 +40,7 @@
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver;
+static bool boost_enabled;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -316,6 +317,29 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot enable boost!\n", __func__);
+ return -EINVAL;
+ }
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -1898,6 +1922,65 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_trigger_state_sw(void)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table)
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ }
+
+ return ret;
+
+}
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (boost_enabled != state) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ boost_enabled = state;
+ if (cpufreq_driver->enable_boost)
+ ret = cpufreq_driver->enable_boost(state);
+ else
+ ret = cpufreq_boost_trigger_state_sw();
+
+ if (ret) {
+ boost_enabled = 0;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ pr_err("%s: BOOST cannot enable (%d)\n",
+ __func__, ret);
+
+ return ret;
+ }
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ state ? "enabled" : "disabled");
+ }
+
+ return 0;
+}
+
+int cpufreq_boost_supported(void)
+{
+ return cpufreq_driver->boost_supported;
+}
+
+int cpufreq_boost_enabled(void)
+{
+ return boost_enabled;
+}
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (!cpufreq_driver->boost_supported)
+ boost.attr.mode = 0444;
+
+ ret = cpufreq_sysfs_create_file(&(boost.attr));
+ if (ret) {
+ pr_err("%s: cannot register global boost sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
goto err_null_driver;
@@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+
+ cpufreq_sysfs_remove_file(&(boost.attr));
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
list_del(&cpufreq_policy_list);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a7966..9c8e71e 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,6 +34,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (cpufreq_boost_supported())
+ if (!cpufreq_boost_enabled()
+ && table[i].index == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u index\n",
i, freq, table[i].index);
if (freq < min_freq)
@@ -171,7 +176,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ int show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,6 +192,9 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -194,14 +203,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show normal boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 0);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 1);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 5348981..4783c4c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -267,6 +267,10 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ int (*enable_boost) (int state);
};
/* flags */
@@ -408,6 +412,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST_FREQ ~2
+
struct cpufreq_frequency_table {
unsigned int index; /* any */
unsigned int frequency; /* kHz - doesn't need to be in ascending
@@ -426,11 +433,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
The struct cpufreq_driver has been extended to embrace the information
related to boost support.
When "boost_mode" device tree attribute is defined for a platform, the
boost_supported flag is set. Moreover boost related attributes were
exported.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
---
drivers/cpufreq/exynos-cpufreq.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 3197d88..b0e424e 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -264,6 +264,7 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_scaling_boost_freqs,
NULL,
};
@@ -359,6 +360,7 @@ static struct of_device_id exynos_cpufreq_of_match[] __initconst = {
static int __init exynos_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -391,6 +393,8 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
}
locking_frequency = exynos_getspeed(0);
+ if (of_property_read_bool(node, "boost_mode"))
+ exynos_driver.boost_supported = 1;
register_pm_notifier(&exynos_cpufreq_nb);
--
1.7.10.4
In the core governor code, per cpu load value is calculated. This patch
uses it to mark processor as a "busy" one, when load value is higher than
90%.
New cpufreq sysfs attribute is created (busy_cpus). It is read only
and provides information about number of actually busy CPU.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- New patch
---
drivers/cpufreq/cpufreq.c | 31 ++++++++++++++++++++++++++++++-
drivers/cpufreq/cpufreq_governor.c | 1 +
include/linux/cpufreq.h | 3 +++
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 9141d33..f785273 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -48,6 +48,7 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
static DEFINE_RWLOCK(cpufreq_driver_lock);
static LIST_HEAD(cpufreq_policy_list);
+static cpumask_t cpufreq_busy_cpus;
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -317,6 +318,13 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_busy_cpus(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_num_busy_cpu());
+}
+define_one_global_ro(busy_cpus);
+
ssize_t show_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -1980,6 +1988,17 @@ int cpufreq_boost_enabled(void)
return boost_enabled;
}
+int cpufreq_num_busy_cpu(void)
+{
+ return cpumask_weight(&cpufreq_busy_cpus);
+}
+
+void cpufreq_set_busy_cpu(int cpu, int val)
+{
+ val ? cpumask_set_cpu(cpu, &cpufreq_busy_cpus) :
+ cpumask_clear_cpu(cpu, &cpufreq_busy_cpus);
+}
+
/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2019,6 +2038,13 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ ret = cpufreq_sysfs_create_file(&(busy_cpus.attr));
+ if (ret) {
+ pr_err("%s: cannot register global busy_cpus sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+
if (!cpufreq_driver->boost_supported)
boost.attr.mode = 0444;
@@ -2026,7 +2052,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (ret) {
pr_err("%s: cannot register global boost sysfs file\n",
__func__);
- goto err_null_driver;
+ goto err_busy_idle_unreg;
}
ret = subsys_interface_register(&cpufreq_interface);
@@ -2058,6 +2084,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_busy_idle_unreg:
+ cpufreq_sysfs_remove_file(&(busy_cpus.attr));
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2086,6 +2114,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
subsys_interface_unregister(&cpufreq_interface);
+ cpufreq_sysfs_remove_file(&(busy_cpus.attr));
cpufreq_sysfs_remove_file(&(boost.attr));
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 077cea7..3402533 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -148,6 +148,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
continue;
load = 100 * (wall_time - idle_time) / wall_time;
+ cpufreq_set_busy_cpu(j, load > 90 ? 1 : 0);
if (dbs_data->cdata->governor == GOV_ONDEMAND) {
int freq_avg = __cpufreq_driver_getavg(policy, j);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 4783c4c..536abfc 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -436,6 +436,9 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
int cpufreq_boost_trigger_state(int state);
int cpufreq_boost_supported(void);
int cpufreq_boost_enabled(void);
+
+void cpufreq_set_busy_cpu(int cpu, int val);
+int cpufreq_num_busy_cpu(void);
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
--
1.7.10.4
This patch adds protection from accidental enable of boost at systems,
which supports software boosting.
Boost software mode can be only enabled when up to one busy (with heavy
load) core is available on the system. Such approach brings extra
protection from over heating.
Moreover the boost is automatically disabled, when cpufreq core detects
more busy cores.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- New patch
---
drivers/cpufreq/cpufreq.c | 9 +++++++--
drivers/cpufreq/cpufreq_governor.c | 3 +++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f785273..59d2cac 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1932,12 +1932,17 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
/*********************************************************************
* BOOST *
*********************************************************************/
-static int cpufreq_boost_trigger_state_sw(void)
+static int cpufreq_boost_trigger_state_sw(int state)
{
struct cpufreq_frequency_table *freq_table;
struct cpufreq_policy *policy;
int ret = -EINVAL;
+ if (state && cpufreq_num_busy_cpu() > 1) {
+ boost_enabled = 0;
+ return 0;
+ }
+
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
if (freq_table)
@@ -1959,7 +1964,7 @@ int cpufreq_boost_trigger_state(int state)
if (cpufreq_driver->enable_boost)
ret = cpufreq_driver->enable_boost(state);
else
- ret = cpufreq_boost_trigger_state_sw();
+ ret = cpufreq_boost_trigger_state_sw(state);
if (ret) {
boost_enabled = 0;
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 3402533..9383ab9 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -162,6 +162,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
max_load = load;
}
+ if (cpufreq_boost_supported() && cpufreq_num_busy_cpu() > 1)
+ cpufreq_boost_trigger_state(0);
+
dbs_data->cdata->gov_check_cpu(cpu, max_load);
}
EXPORT_SYMBOL_GPL(dbs_check_cpu);
--
1.7.10.4
This patch provides support for disabling cpufreq's boost
feature when thermal trip point is reached.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- New patch
---
drivers/thermal/cpu_cooling.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index c94bf2e..3bdd870 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -323,6 +323,9 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
if (cpumask_test_cpu(policy->cpu, ¬ify_device->allowed_cpus))
max_freq = notify_device->cpufreq_val;
+ if (cpufreq_boost_supported())
+ cpufreq_boost_trigger_state(0);
+
/* Never exceed user_policy.max */
if (max_freq > policy->user_policy.max)
max_freq = policy->user_policy.max;
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is always visible.
When cpufreq driver doesn't support boost, it is read only.
The boost supported global flag was replaced with the one defined at acpi's
cpufreq driver.
The _store_boost() function has been redesigned to be used as set_boost_freq
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
---
drivers/cpufreq/acpi-cpufreq.c | 61 ++++++++++++++--------------------------
1 file changed, 21 insertions(+), 40 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 2845566..f33a3c9 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,7 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
+static bool boost_enabled;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,20 +133,10 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
+ return 0;
get_online_cpus();
@@ -157,30 +147,31 @@ static ssize_t _store_boost(const char *buf, size_t count)
boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
+ return 0;
}
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_boost(const char *buf, size_t count)
{
- return _store_boost(buf, count);
-}
+ int ret;
+ unsigned long val = 0;
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
-}
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
+ _store_boost((int) val);
+
+ return count;
+}
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
@@ -920,6 +911,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
+ .enable_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -930,8 +922,8 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
boost_enabled = boost_state(0);
+ acpi_cpufreq_driver.boost_supported = true;
get_online_cpus();
@@ -941,22 +933,11 @@ static void __init acpi_cpufreq_boost_init(void)
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
--
1.7.10.4
Policies available in a cpufreq framework are now linked together. They are
accessible via cpufreq_policy_list defined at cpufreq core.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Changes for v4:
- New patch
---
drivers/cpufreq/cpufreq.c | 3 +++
include/linux/cpufreq.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2ce86ed..665e641 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -46,6 +46,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
static DEFINE_RWLOCK(cpufreq_driver_lock);
+static LIST_HEAD(cpufreq_policy_list);
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -989,6 +990,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
}
#endif
+ list_add(&policy->policy_list, &cpufreq_policy_list);
ret = cpufreq_add_dev_interface(cpu, policy, dev);
if (ret)
goto err_out_unregister;
@@ -1992,6 +1994,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
subsys_interface_unregister(&cpufreq_interface);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
+ list_del(&cpufreq_policy_list);
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ab1932c..5348981 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -117,6 +117,7 @@ struct cpufreq_policy {
struct cpufreq_real_policy user_policy;
+ struct list_head policy_list;
struct kobject kobj;
struct completion kobj_unregister;
};
--
1.7.10.4
On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> This commit adds boost frequency support in cpufreq core (Hardware &
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + if (!cpufreq_driver->boost_supported)
> + boost.attr.mode = 0444;
> +
> + ret = cpufreq_sysfs_create_file(&(boost.attr));
> + if (ret) {
> + pr_err("%s: cannot register global boost sysfs file\n",
> + __func__);
> + goto err_null_driver;
> + }
> +
I do not think the boost sysfs should be created at all if boost is not
supported.
For intel_pstate the read-only boost would be there for no reason and would
cause confusion on the part of the user IMHO
> ret = subsys_interface_register(&cpufreq_interface);
> if (ret)
> goto err_null_driver;
> @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> pr_debug("unregistering driver %s\n", driver->name);
>
> subsys_interface_unregister(&cpufreq_interface);
> +
> + cpufreq_sysfs_remove_file(&(boost.attr));
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> In the core governor code, per cpu load value is calculated. This patch
> uses it to mark processor as a "busy" one, when load value is higher than
> 90%.
>
> New cpufreq sysfs attribute is created (busy_cpus). It is read only
> and provides information about number of actually busy CPU.
>
What is the intended use of this interface?
For drivers that have internal governors it will be misleading/wrong
--Dirk
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> Changes for v4:
> - New patch
> ---
> drivers/cpufreq/cpufreq.c | 31 ++++++++++++++++++++++++++++++-
> drivers/cpufreq/cpufreq_governor.c | 1 +
> include/linux/cpufreq.h | 3 +++
> 3 files changed, 34 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 9141d33..f785273 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -48,6 +48,7 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
> #endif
> static DEFINE_RWLOCK(cpufreq_driver_lock);
> static LIST_HEAD(cpufreq_policy_list);
> +static cpumask_t cpufreq_busy_cpus;
>
> /*
> * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
> @@ -317,6 +318,13 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
> /*********************************************************************
> * SYSFS INTERFACE *
> *********************************************************************/
> +ssize_t show_busy_cpus(struct kobject *kobj,
> + struct attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%d\n", cpufreq_num_busy_cpu());
> +}
> +define_one_global_ro(busy_cpus);
> +
> ssize_t show_boost(struct kobject *kobj,
> struct attribute *attr, char *buf)
> {
> @@ -1980,6 +1988,17 @@ int cpufreq_boost_enabled(void)
> return boost_enabled;
> }
>
> +int cpufreq_num_busy_cpu(void)
> +{
> + return cpumask_weight(&cpufreq_busy_cpus);
> +}
> +
> +void cpufreq_set_busy_cpu(int cpu, int val)
> +{
> + val ? cpumask_set_cpu(cpu, &cpufreq_busy_cpus) :
> + cpumask_clear_cpu(cpu, &cpufreq_busy_cpus);
> +}
> +
> /*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
> @@ -2019,6 +2038,13 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + ret = cpufreq_sysfs_create_file(&(busy_cpus.attr));
> + if (ret) {
> + pr_err("%s: cannot register global busy_cpus sysfs file\n",
> + __func__);
> + goto err_null_driver;
> + }
> +
> if (!cpufreq_driver->boost_supported)
> boost.attr.mode = 0444;
>
> @@ -2026,7 +2052,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> if (ret) {
> pr_err("%s: cannot register global boost sysfs file\n",
> __func__);
> - goto err_null_driver;
> + goto err_busy_idle_unreg;
> }
>
> ret = subsys_interface_register(&cpufreq_interface);
> @@ -2058,6 +2084,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> return 0;
> err_if_unreg:
> subsys_interface_unregister(&cpufreq_interface);
> +err_busy_idle_unreg:
> + cpufreq_sysfs_remove_file(&(busy_cpus.attr));
> err_null_driver:
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> cpufreq_driver = NULL;
> @@ -2086,6 +2114,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
>
> subsys_interface_unregister(&cpufreq_interface);
>
> + cpufreq_sysfs_remove_file(&(busy_cpus.attr));
> cpufreq_sysfs_remove_file(&(boost.attr));
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
> index 077cea7..3402533 100644
> --- a/drivers/cpufreq/cpufreq_governor.c
> +++ b/drivers/cpufreq/cpufreq_governor.c
> @@ -148,6 +148,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
> continue;
>
> load = 100 * (wall_time - idle_time) / wall_time;
> + cpufreq_set_busy_cpu(j, load > 90 ? 1 : 0);
>
> if (dbs_data->cdata->governor == GOV_ONDEMAND) {
> int freq_avg = __cpufreq_driver_getavg(policy, j);
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 4783c4c..536abfc 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -436,6 +436,9 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
> int cpufreq_boost_trigger_state(int state);
> int cpufreq_boost_supported(void);
> int cpufreq_boost_enabled(void);
> +
> +void cpufreq_set_busy_cpu(int cpu, int val);
> +int cpufreq_num_busy_cpu(void);
> /* the following 3 funtions are for cpufreq core use only */
> struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
>
>
On Wed, 19 Jun 2013 10:48:53 -0700
Dirk Brandewie <[email protected]> wrote:
> On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > This commit adds boost frequency support in cpufreq core (Hardware &
>
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + if (!cpufreq_driver->boost_supported)
> > + boost.attr.mode = 0444;
> > +
> > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> > + if (ret) {
> > + pr_err("%s: cannot register global boost sysfs
> > file\n",
> > + __func__);
> > + goto err_null_driver;
> > + }
> > +
>
> I do not think the boost sysfs should be created at all if boost is
> not supported.
This was my first thought. But unfortunately this "boost" attribute is
always exported at acpi-cpufreq.c and in my opinion is part of a
legacy API.
I totally agree with the idea of exporting boost only when supported,
but I would like to know the community opinion about this (especially
Viresh and Rafael shall speak up).
>
> For intel_pstate the read-only boost would be there for no reason and
> would cause confusion on the part of the user IMHO
You are probably right here. However I don't know what was the
original rationale behind exporting this attribute as read only.
>
> > ret = subsys_interface_register(&cpufreq_interface);
> > if (ret)
> > goto err_null_driver;
> > @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> > subsys_interface_unregister(&cpufreq_interface);
> > +
> > + cpufreq_sysfs_remove_file(&(boost.attr));
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
>
Best regards,
Lukasz Majewski
On Wed, 19 Jun 2013 11:01:07 -0700
Dirk Brandewie <[email protected]> wrote:
> On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > In the core governor code, per cpu load value is calculated. This
> > patch uses it to mark processor as a "busy" one, when load value is
> > higher than 90%.
> >
> > New cpufreq sysfs attribute is created (busy_cpus). It is read only
> > and provides information about number of actually busy CPU.
> >
>
> What is the intended use of this interface?
The kernel API would be handy with boost managed by software (like it is
done with exynos) and with LAB governor.
The intention is to have two save valves for boost:
1. Enable SW controlled boost only when we have just one busy CPU.
2. Use the Thermal subsystem to switch off SW managed boost when it
detects that SoC is overheating.
The problem with 2 is that, the boost code is compiled in to the cpufreq
core (no CONFIG_BOOST flag). Thereof we cannot guarantee, that thermal
would be always enabled (the KConfig select option).
I think that thermal subsystem is a suitable place to disable SW boost
at emergency. However in my opinion this is not enough and precaution
defined at 1 is needed.
I can remove exporting the "busy_cpu" sysfs attribute if you think, that
it would confuse userspace. Its purpose is mainly informational.
>
> For drivers that have internal governors it will be misleading/wrong
Would you be so kind and give me an example of such an internal
governor?
Maybe I've overlooked some important information/usecase.
>
> --Dirk
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > Changes for v4:
> > - New patch
> > ---
> > drivers/cpufreq/cpufreq.c | 31
> > ++++++++++++++++++++++++++++++- drivers/cpufreq/cpufreq_governor.c
> > | 1 + include/linux/cpufreq.h | 3 +++
> > 3 files changed, 34 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 9141d33..f785273 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -48,6 +48,7 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN],
> > cpufreq_cpu_governor); #endif
> > static DEFINE_RWLOCK(cpufreq_driver_lock);
> > static LIST_HEAD(cpufreq_policy_list);
> > +static cpumask_t cpufreq_busy_cpus;
> >
> > /*
> > * cpu_policy_rwsem is a per CPU reader-writer semaphore designed
> > to cure @@ -317,6 +318,13 @@
> > EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /*********************************************************************
> > * SYSFS
> > INTERFACE *
> > *********************************************************************/
> > +ssize_t show_busy_cpus(struct kobject *kobj,
> > + struct attribute *attr, char *buf)
> > +{
> > + return sprintf(buf, "%d\n", cpufreq_num_busy_cpu());
> > +}
> > +define_one_global_ro(busy_cpus);
> > +
> > ssize_t show_boost(struct kobject *kobj,
> > struct attribute *attr, char
> > *buf) {
> > @@ -1980,6 +1988,17 @@ int cpufreq_boost_enabled(void)
> > return boost_enabled;
> > }
> >
> > +int cpufreq_num_busy_cpu(void)
> > +{
> > + return cpumask_weight(&cpufreq_busy_cpus);
> > +}
> > +
> > +void cpufreq_set_busy_cpu(int cpu, int val)
> > +{
> > + val ? cpumask_set_cpu(cpu, &cpufreq_busy_cpus) :
> > + cpumask_clear_cpu(cpu, &cpufreq_busy_cpus);
> > +}
> > +
> > /*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> > @@ -2019,6 +2038,13 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + ret = cpufreq_sysfs_create_file(&(busy_cpus.attr));
> > + if (ret) {
> > + pr_err("%s: cannot register global busy_cpus sysfs
> > file\n",
> > + __func__);
> > + goto err_null_driver;
> > + }
> > +
> > if (!cpufreq_driver->boost_supported)
> > boost.attr.mode = 0444;
> >
> > @@ -2026,7 +2052,7 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) if (ret) {
> > pr_err("%s: cannot register global boost sysfs
> > file\n", __func__);
> > - goto err_null_driver;
> > + goto err_busy_idle_unreg;
> > }
> >
> > ret = subsys_interface_register(&cpufreq_interface);
> > @@ -2058,6 +2084,8 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) return 0;
> > err_if_unreg:
> > subsys_interface_unregister(&cpufreq_interface);
> > +err_busy_idle_unreg:
> > + cpufreq_sysfs_remove_file(&(busy_cpus.attr));
> > err_null_driver:
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > cpufreq_driver = NULL;
> > @@ -2086,6 +2114,7 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver)
> >
> > subsys_interface_unregister(&cpufreq_interface);
> >
> > + cpufreq_sysfs_remove_file(&(busy_cpus.attr));
> > cpufreq_sysfs_remove_file(&(boost.attr));
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > diff --git a/drivers/cpufreq/cpufreq_governor.c
> > b/drivers/cpufreq/cpufreq_governor.c index 077cea7..3402533 100644
> > --- a/drivers/cpufreq/cpufreq_governor.c
> > +++ b/drivers/cpufreq/cpufreq_governor.c
> > @@ -148,6 +148,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data,
> > int cpu) continue;
> >
> > load = 100 * (wall_time - idle_time) / wall_time;
> > + cpufreq_set_busy_cpu(j, load > 90 ? 1 : 0);
> >
> > if (dbs_data->cdata->governor == GOV_ONDEMAND) {
> > int freq_avg =
> > __cpufreq_driver_getavg(policy, j); diff --git
> > a/include/linux/cpufreq.h b/include/linux/cpufreq.h index
> > 4783c4c..536abfc 100644 --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -436,6 +436,9 @@ int cpufreq_frequency_table_target(struct
> > cpufreq_policy *policy, int cpufreq_boost_trigger_state(int state);
> > int cpufreq_boost_supported(void);
> > int cpufreq_boost_enabled(void);
> > +
> > +void cpufreq_set_busy_cpu(int cpu, int val);
> > +int cpufreq_num_busy_cpu(void);
> > /* the following 3 funtions are for cpufreq core use only */
> > struct cpufreq_frequency_table
> > *cpufreq_frequency_get_table(unsigned int cpu);
> >
> >
>
Best regards,
Lukasz Majewski
On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
> On Wed, 19 Jun 2013 10:48:53 -0700
> Dirk Brandewie <[email protected]> wrote:
>
> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > > This commit adds boost frequency support in cpufreq core (Hardware &
> >
> > > +/*********************************************************************
> > > * REGISTER / UNREGISTER CPUFREQ
> > > DRIVER *
> > > *********************************************************************/
> > >
> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > >
> > > + if (!cpufreq_driver->boost_supported)
> > > + boost.attr.mode = 0444;
> > > +
> > > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> > > + if (ret) {
> > > + pr_err("%s: cannot register global boost sysfs
> > > file\n",
> > > + __func__);
> > > + goto err_null_driver;
> > > + }
> > > +
> >
> > I do not think the boost sysfs should be created at all if boost is
> > not supported.
>
> This was my first thought. But unfortunately this "boost" attribute is
> always exported at acpi-cpufreq.c and in my opinion is part of a
> legacy API.
>
> I totally agree with the idea of exporting boost only when supported,
> but I would like to know the community opinion about this (especially
> Viresh and Rafael shall speak up).
Simple: Export it only when supported.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Wednesday, June 19, 2013 10:58:32 PM Lukasz Majewski wrote:
> On Wed, 19 Jun 2013 11:01:07 -0700
> Dirk Brandewie <[email protected]> wrote:
>
> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > > In the core governor code, per cpu load value is calculated. This
> > > patch uses it to mark processor as a "busy" one, when load value is
> > > higher than 90%.
> > >
> > > New cpufreq sysfs attribute is created (busy_cpus). It is read only
> > > and provides information about number of actually busy CPU.
> > >
> >
> > What is the intended use of this interface?
>
> The kernel API would be handy with boost managed by software (like it is
> done with exynos) and with LAB governor.
>
> The intention is to have two save valves for boost:
>
> 1. Enable SW controlled boost only when we have just one busy CPU.
>
> 2. Use the Thermal subsystem to switch off SW managed boost when it
> detects that SoC is overheating.
>
> The problem with 2 is that, the boost code is compiled in to the cpufreq
> core (no CONFIG_BOOST flag). Thereof we cannot guarantee, that thermal
> would be always enabled (the KConfig select option).
> I think that thermal subsystem is a suitable place to disable SW boost
> at emergency. However in my opinion this is not enough and precaution
> defined at 1 is needed.
>
> I can remove exporting the "busy_cpu" sysfs attribute if you think, that
> it would confuse userspace. Its purpose is mainly informational.
>
> >
> > For drivers that have internal governors it will be misleading/wrong
>
> Would you be so kind and give me an example of such an internal
> governor?
>
> Maybe I've overlooked some important information/usecase.
Please look at intel_pstate.c.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On 18 June 2013 19:14, Lukasz Majewski <[email protected]> wrote:
> On Tue, 18 Jun 2013 15:26:16 +0200, Rafael J. Wysocki wrote:
>> On Tuesday, June 18, 2013 12:12:13 PM Viresh Kumar wrote:
>> > On 17 June 2013 19:21, Lukasz Majewski <[email protected]>
>> Well, that's why on x86 turbo is controlled by hardware that takes
>> care of keeping things within the chip's thermal limits.
>
> And this is the reason why I don't want to overly change acpi-cpufreq.c
> code. :-)
We need to keep both hardware/software boost features at the same place
in core, they may behave differently though. That's why I wanted you
to do that.
> I think that thermal subsystem shall be the second option to disable SW
> boosting.
>
> The main control shall be done inside the cpufreq core. The idea to
> disable boost when more than one core is active is rational.
But then, it might not be enough. A single core can make your SoC
very hot.
On 18 June 2013 18:56, Rafael J. Wysocki <[email protected]> wrote:
> On Tuesday, June 18, 2013 12:12:13 PM Viresh Kumar wrote:
>> On 17 June 2013 19:21, Lukasz Majewski <[email protected]> wrote:
>> According to my understanding, boost was important for power
>> saving. In case a high load can be managed by a single cpu with
>> boost freqs, then its better to use boost freqs rather than bringing
>> another cpu up.
>
> Do you mean the 'boost' sysfs attribute or the 'turbo frequencies' concept?
I thought they are the. Probably not, but I am not sure about the
difference.
>> Normally boost freqs are not so useful if we talk about powersaving,
>> as their energy consumption is much higher with not so great impact
>> on performance.
>
> Er, er, please be careful here. The impact on performance may be sufficient
> for deep C-states to become relevant in some cases.
Hmm.
>> That's why when this thread started we talked about boost only when
>> one cpu is operational. But with your patch all cores can use boost
>> freq and thermal will come into picture just to save the chip.
>
> Well, that's why on x86 turbo is controlled by hardware that takes care of
> keeping things within the chip's thermal limits.
Yeah.
>> That's wrong. This isn't why we invented boost here. Otherwise you
>> just don't need boost feature at all for your SoC. Just make these
>> freqs as available freqs and let thermal control policy->max/min
>> to save your chip.
>
> The 'boost' attribute added by acpi-cpufreq means "let the hardware use turbo
> frequencies".
>
> I'd recommend you both to read Documentation/cpu-freq/boost.txt now. :-)
I did it now :)
> I think we can extend the meaning to "let turbo frequencies be used", but if
> we need software to play the role of the hardware's thermal control, we need
> to be very careful.
Exactly. There are two variants now:
- Hardware boost: x86: Don't do any trick in software to prevent hardware
from boosting... Let the hardware take control as it is today
- Software boost: The initial idea from Lukasz was about using boost only
when one cpu is used. That's the impression I had in mind. And it looked
sensible too to some extent. BUT there is a great chance that any mistake
can burn chips, so we need to be extremely careful.
>> What we probably need is:
>> - Enabled boost from sysfs if required (now below steps will come into
>> picture)
>
> This has to be compatible with the existing stuff.
Sure.
>> - See how many cpus are running, if only one then start using boost freqs
>> - Now thermal should be come into picture to save chip in case a single
>> cpu running at boost can burn it out.
>
> I'd say there needs to be a separate controller/monitor for that that will
> know what the chip's thermal limit is and how that relates to how fast the
> CPU core(s) may run and for how much time. I'm not sure it is sufficient
> to "wait for thermal to kick in" here, because you may need to slow down
> things in advance (i.e. before thermal sensors tell you there's too much heat,
> because that may be too late already).
That's why I wasn't sure about software boosting initially. But at the same
time a thermal sensor might be good enough. They just have to be programmed
accordingly, so that they fire a bit in advance before things are out of
control. :)
On 19 June 2013 12:46, Lukasz Majewski <[email protected]> wrote:
> I would like to clarify the above issue.
>
> When I've discussed with Viresh previous version of this patch, we have
> agreed, that "boost" sysfs attribute [*]:
> /sys/devices/system/cpu/cpufreq/boost
>
> would be only visible when boost_supported flag is set at cpufreq
> driver.
Yes.
> When acpi-cpufreq driver doesn't support boost, the attribute [*]
> won't be exported at all. This contradicts the documentation and legacy
> acpi-cpufreq behaviour.
No they aren't contradictory. What the documentation meant was:
acpi-cpufreq driver is used by lots of different x86 processors. Now
all processors might not support boost inside x86 also. And for them
we will keep 'boost' file readonly. This is done by following statement
if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) {
boost_supported = true;
....
} else
global_boost.attr.mode = 0444;
Documentation file doesn't talk about any other cpufreq driver, for
them there is no concept like boost.
You need to preserve this functionality.
> Since I'm affraid to break API (with all its consequences :-) ), I would
> like to be sure that this is OK, and thereof I'm allowed to rewrite
> documentation accordingly.
>
> I simply need explicit permission from both maintainers :-).
For me its okay to rewrite documentation.
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> Boost sysfs attribute is always exported (to support legacy API). By
> default boost is exported as read only. One global attribute is available at:
> /sys/devices/system/cpu/cpufreq/boost.
You asked me and Rafael a question and posted your next version without
even waiting for our replies? That will waste your time and ours too
reviewing it.
On Thu, 20 Jun 2013 10:41:41 +0530, Viresh Kumar wrote:
> On 19 June 2013 12:46, Lukasz Majewski <[email protected]> wrote:
> > I would like to clarify the above issue.
> >
> > When I've discussed with Viresh previous version of this patch, we
> > have agreed, that "boost" sysfs attribute [*]:
> > /sys/devices/system/cpu/cpufreq/boost
> >
> > would be only visible when boost_supported flag is set at cpufreq
> > driver.
>
> Yes.
>
> > When acpi-cpufreq driver doesn't support boost, the attribute [*]
> > won't be exported at all. This contradicts the documentation and
> > legacy acpi-cpufreq behaviour.
>
> No they aren't contradictory. What the documentation meant was:
> acpi-cpufreq driver is used by lots of different x86 processors. Now
> all processors might not support boost inside x86 also. And for them
> we will keep 'boost' file readonly. This is done by following
> statement
Thanks for explanation.
>
> if (boot_cpu_has(X86_FEATURE_CPB) ||
> boot_cpu_has(X86_FEATURE_IDA)) { boost_supported = true;
> ....
> } else
> global_boost.attr.mode = 0444;
Grrr.... So simple and obvious solution [1].
>
> Documentation file doesn't talk about any other cpufreq driver, for
> them there is no concept like boost.
>
> You need to preserve this functionality.
Yes the idea [1], solves problem with legacy API.
>
> > Since I'm affraid to break API (with all its consequences :-) ), I
> > would like to be sure that this is OK, and thereof I'm allowed to
> > rewrite documentation accordingly.
> >
> > I simply need explicit permission from both maintainers :-).
>
> For me its okay to rewrite documentation.
I will extent documentation about the SW managed boost.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thu, 20 Jun 2013 10:31:30 +0530, Viresh Kumar wrote:
> > I'd say there needs to be a separate controller/monitor for that
> > that will know what the chip's thermal limit is and how that
> > relates to how fast the CPU core(s) may run and for how much time.
> > I'm not sure it is sufficient to "wait for thermal to kick in"
> > here, because you may need to slow down things in advance (i.e.
> > before thermal sensors tell you there's too much heat, because that
> > may be too late already).
>
> That's why I wasn't sure about software boosting initially. But at
> the same time a thermal sensor might be good enough. They just have
> to be programmed accordingly, so that they fire a bit in advance
> before things are out of control. :)
I think that thermal subsystem shall disable boost when SoC is heated
up.
The problem is to guarantee, that thermal will be always enabled and
correctly configured when software based boost is ready to run.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thursday, June 20, 2013 10:43:08 AM Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
>
> > Boost sysfs attribute is always exported (to support legacy API). By
> > default boost is exported as read only. One global attribute is available at:
> > /sys/devices/system/cpu/cpufreq/boost.
>
> You asked me and Rafael a question and posted your next version without
> even waiting for our replies? That will waste your time and ours too
> reviewing it.
I believe I replied to that (in a different branch of the thread).
And the reply was: Do not expose if not supported.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Thu, 20 Jun 2013 22:03:45 +0200, Rafael J. Wysocki wrote:
Hi Rafael,
> On Thursday, June 20, 2013 10:43:08 AM Viresh Kumar wrote:
> > On 19 June 2013 22:42, Lukasz Majewski <[email protected]>
> > wrote:
> >
> > > Boost sysfs attribute is always exported (to support legacy API).
> > > By default boost is exported as read only. One global attribute
> > > is available at: /sys/devices/system/cpu/cpufreq/boost.
> >
> > You asked me and Rafael a question and posted your next version
> > without even waiting for our replies? That will waste your time and
> > ours too reviewing it.
>
> I believe I replied to that (in a different branch of the thread).
>
> And the reply was: Do not expose if not supported.
Thanks for reply. Understood :-)
>
> Thanks,
> Rafael
>
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Hi Viresh,
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB
> component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to
> include common code.
>
> Important design decisions:
>
> - Boost related code is compiled-in unconditionally and disabled by
> default The cpufreq_driver is responsibile for setting
> boost_supported flag and providing enable_boost callback(if HW
> support is needed)
>
> - struct cpufreq_driver has been extended with boost related fields:
> -- boost_supported - when driver supports boosting
> -- enable_boost - callback to function, which is necessary to
> enable boost in the processor (like it is done at Intel)
>
> - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is
> always provided.
> It will be read only, until either cpufreq_driver defines
> boost_supported flag or device tree's cpufreq "boost_mode" attribute
> is defined. It is consistent with legacy acpi API.
>
> - No special spin_lock for Boost was created. The one from cpufreq
> core was reused.
>
> - All available policies are now stored in a list.
>
> - The Boost code doesn't rely on any policy. When boost state is
> changed, then the policy list is iterated and proper adjustements are
> done.
>
> - Number of busy cpus (with load > 90%) is calculated and exported as
> a global sysfs attribute.
>
> - The SW based boost can be only enabled when up to one core is
> regarded as a "busy" one. For safety reasons boost is disabled when
> more cores comes into play.
>
> - To improve safety level, the thermal framework is also extended to
> disable software boosting, when thermal trip point is reached.
>
> New patches for v4:
> cpufreq: Store cpufreq policies in a list
> cpufreq: Calculate number of busy CPUs
> cpufreq: Enable software boost only when up to one busy core is
> running thermal:boost: Disable boost when trip point is reached
>
> Tested at: HW:
> Exynos 4412 3.10 linux
> Exynos 4210 3.10 linux
> Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem)
> test needed
>
If this is not a problem, I'd like to kindly ask You to review those
patches.
Rafael has expressed his opinion about "boost" attribute clearly at the
other mail (as a response to v4 patches):
"Simple: Export it only when supported."
Despite the change about the "boost" attribute visibility there were
many other changes, which deserve maintainer's look.
>
> Lukasz Majewski (7):
> cpufreq: Store cpufreq policies in a list
> cpufreq: Add boost frequency support in core
> cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
> boost solution
> cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> framework
> cpufreq: Calculate number of busy CPUs
> cpufreq: Enable software boost only when up to one busy core is
> running
> thermal:boost: Disable boost when trip point is reached
>
> drivers/cpufreq/acpi-cpufreq.c | 61 ++++++-----------
> drivers/cpufreq/cpufreq.c | 132
> ++++++++++++++++++++++++++++++++++++
> drivers/cpufreq/cpufreq_governor.c | 4 ++
> drivers/cpufreq/exynos-cpufreq.c | 4 ++
> drivers/cpufreq/freq_table.c | 43 ++++++++++--
> drivers/thermal/cpu_cooling.c | 3 +
> include/linux/cpufreq.h | 15 ++++ 7 files changed, 215
> insertions(+), 47 deletions(-)
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, Jun 26, 2013 at 1:18 PM, Lukasz Majewski <[email protected]> wrote:
> If this is not a problem, I'd like to kindly ask You to review those
> patches.
>
> Rafael has expressed his opinion about "boost" attribute clearly at the
> other mail (as a response to v4 patches):
> "Simple: Export it only when supported."
>
> Despite the change about the "boost" attribute visibility there were
> many other changes, which deserve maintainer's look.
I haven't got time to review it until now.. I will try to do it this week.
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> Policies available in a cpufreq framework are now linked together. They are
> accessible via cpufreq_policy_list defined at cpufreq core.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> Changes for v4:
> - New patch
You need to write changelog after ---, so that it doesn't get commited.
> ---
> drivers/cpufreq/cpufreq.c | 3 +++
> include/linux/cpufreq.h | 1 +
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 2ce86ed..665e641 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -46,6 +46,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
> #endif
> static DEFINE_RWLOCK(cpufreq_driver_lock);
> +static LIST_HEAD(cpufreq_policy_list);
>
> /*
> * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
> @@ -989,6 +990,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
> }
> #endif
>
> + list_add(&policy->policy_list, &cpufreq_policy_list);
> ret = cpufreq_add_dev_interface(cpu, policy, dev);
> if (ret)
> goto err_out_unregister;
what about handling error cases?
> @@ -1992,6 +1994,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> subsys_interface_unregister(&cpufreq_interface);
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> + list_del(&cpufreq_policy_list);
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> cpufreq_driver = NULL;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index ab1932c..5348981 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -117,6 +117,7 @@ struct cpufreq_policy {
>
> struct cpufreq_real_policy user_policy;
>
> + struct list_head policy_list;
> struct kobject kobj;
> struct completion kobj_unregister;
--
viresh
On 26 Jun 2013 16:05:12,Viresh Kumar <[email protected]> wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> > Policies available in a cpufreq framework are now linked together.
> > They are accessible via cpufreq_policy_list defined at cpufreq core.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > Changes for v4:
> > - New patch
>
> You need to write changelog after ---, so that it doesn't get
> commited.
>
> > ---
So here <---> I will put change log for v5.
> > drivers/cpufreq/cpufreq.c | 3 +++
> > include/linux/cpufreq.h | 1 +
> > 2 files changed, 4 insertions(+)
> >
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 2ce86ed..665e641 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -46,6 +46,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *,
> > cpufreq_cpu_data); static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN],
> > cpufreq_cpu_governor); #endif
> > static DEFINE_RWLOCK(cpufreq_driver_lock);
> > +static LIST_HEAD(cpufreq_policy_list);
> >
> > /*
> > * cpu_policy_rwsem is a per CPU reader-writer semaphore designed
> > to cure @@ -989,6 +990,7 @@ static int cpufreq_add_dev(struct
> > device *dev, struct subsys_interface *sif) }
> > #endif
> >
> > + list_add(&policy->policy_list, &cpufreq_policy_list);
> > ret = cpufreq_add_dev_interface(cpu, policy, dev);
> > if (ret)
I will add list_del(&cpufreq_policy_list);
here.
> > goto err_out_unregister;
>
> what about handling error cases?
Thanks for spotting.
>
> > @@ -1992,6 +1994,7 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver)
> > subsys_interface_unregister(&cpufreq_interface);
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > + list_del(&cpufreq_policy_list);
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > cpufreq_driver = NULL;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index ab1932c..5348981 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -117,6 +117,7 @@ struct cpufreq_policy {
> >
> > struct cpufreq_real_policy user_policy;
> >
> > + struct list_head policy_list;
> > struct kobject kobj;
> > struct completion kobj_unregister;
>
> --
> viresh
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> Boost sysfs attribute is always exported (to support legacy API). By
> default boost is exported as read only. One global attribute is available at:
> /sys/devices/system/cpu/cpufreq/boost.
I assume you are going to fix this as discussed in other threads.
> Changes for v4:
> - Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
> - Introduce cpufreq_boost_supported() method
> - Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
> if frequency shall be skipped
> - Rename set_boost_freq() to enable_boost()
> - cpufreq_attr_available_freq() moved to freq_table.c
> - Use policy list to get access to cpufreq policies
> - Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
> - pr_err corrected ( %sable)
> - Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
> boost is supported]
> - Use either HW (boost_enable) callback or SW managed boost
> - Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
> at SW.
> - Protect boost_enabled manipulation with lock
> - Always export boost attribute (preserve legacy behaviour). When boost
> is not supported this attribute is read only
Very well written changelog. But write it after ---
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 665e641..9141d33 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -40,6 +40,7 @@
> * also protects the cpufreq_cpu_data array.
> */
> static struct cpufreq_driver *cpufreq_driver;
> +static bool boost_enabled;
> static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> #ifdef CONFIG_HOTPLUG_CPU
> /* This one keeps track of the previously set governor of a removed CPU */
> @@ -316,6 +317,29 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
> /*********************************************************************
> * SYSFS INTERFACE *
> *********************************************************************/
> +ssize_t show_boost(struct kobject *kobj,
> + struct attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%d\n", boost_enabled);
> +}
> +
> +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
> + const char *buf, size_t count)
> +{
> + int ret, enable;
> +
> + ret = sscanf(buf, "%d", &enable);
> + if (ret != 1 || enable < 0 || enable > 1)
> + return -EINVAL;
> +
> + if (cpufreq_boost_trigger_state(enable)) {
> + pr_err("%s: Cannot enable boost!\n", __func__);
> + return -EINVAL;
> + }
Probably do boost_enabled = true here.
> + return count;
> +}
> +define_one_global_rw(boost);
> /*********************************************************************
> + * BOOST *
> + *********************************************************************/
> +static int cpufreq_boost_trigger_state_sw(void)
> +{
> + struct cpufreq_frequency_table *freq_table;
> + struct cpufreq_policy *policy;
> + int ret = -EINVAL;
> +
> + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
> + freq_table = cpufreq_frequency_get_table(policy->cpu);
> + if (freq_table)
> + ret = cpufreq_frequency_table_cpuinfo(policy,
> + freq_table);
> + }
> +
> + return ret;
> +
> +}
add blank line here.
> +int cpufreq_boost_trigger_state(int state)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + if (boost_enabled != state) {
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + boost_enabled = state;
> + if (cpufreq_driver->enable_boost)
> + ret = cpufreq_driver->enable_boost(state);
> + else
> + ret = cpufreq_boost_trigger_state_sw();
> +
> + if (ret) {
> + boost_enabled = 0;
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> + pr_err("%s: BOOST cannot enable (%d)\n",
> + __func__, ret);
> +
> + return ret;
> + }
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
You can rewrite if (ret) and unlock() code to make it less redundant.
unlock and return ret at the end and write other stuff before it.
> + pr_debug("%s: cpufreq BOOST %s\n", __func__,
> + state ? "enabled" : "disabled");
> + }
> +
> + return 0;
> +}
> +
> +int cpufreq_boost_supported(void)
> +{
> + return cpufreq_driver->boost_supported;
> +}
> +
> +int cpufreq_boost_enabled(void)
> +{
> + return boost_enabled;
> +}
EXPORT_SYMBOL_GPL ??
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + if (!cpufreq_driver->boost_supported)
> + boost.attr.mode = 0444;
> +
> + ret = cpufreq_sysfs_create_file(&(boost.attr));
> + if (ret) {
> + pr_err("%s: cannot register global boost sysfs file\n",
> + __func__);
> + goto err_null_driver;
> + }
This would change.
> ret = subsys_interface_register(&cpufreq_interface);
> if (ret)
> goto err_null_driver;
> @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> pr_debug("unregistering driver %s\n", driver->name);
>
> subsys_interface_unregister(&cpufreq_interface);
> +
> + cpufreq_sysfs_remove_file(&(boost.attr));
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> list_del(&cpufreq_policy_list);
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index d7a7966..9c8e71e 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -34,6 +34,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
>
> continue;
> }
> + if (cpufreq_boost_supported())
Probably remove this check. Assume somebody while testing exynos,
just sent boost_supported as false. Then you will not skip this frequency
and may burn your chip :)
> + if (!cpufreq_boost_enabled()
> + && table[i].index == CPUFREQ_BOOST_FREQ)
> + continue;
This should be enough.
> pr_debug("table entry %u: %u kHz, %u index\n",
> i, freq, table[i].index);
> if (freq < min_freq)
> @@ -171,7 +176,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
> /**
> * show_available_freqs - show available frequencies for the specified CPU
> */
> -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
> + int show_boost)
> {
> unsigned int i = 0;
> unsigned int cpu = policy->cpu;
> @@ -186,6 +192,9 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
> if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> continue;
Add a comment here describing your complex logic.
> + if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
> + continue;
> +
> count += sprintf(&buf[count], "%d ", table[i].frequency);
> }
> count += sprintf(&buf[count], "\n");
> @@ -194,14 +203,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
>
> }
>
> -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> - .attr = { .name = "scaling_available_frequencies",
> - .mode = 0444,
> - },
> - .show = show_available_freqs,
> -};
> +#define cpufreq_attr_available_freq(_name) \
> +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
> +__ATTR_RO(_name##_frequencies)
> +
> +/**
> + * show_scaling_available_frequencies - show normal boost frequencies for
You missed this comment earlier. boost??
> + * the specified CPU
> + */
> +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 0);
> +}
> +cpufreq_attr_available_freq(scaling_available);
> EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
>
> +/**
> + * show_available_boost_freqs - show available boost frequencies for
> + * the specified CPU
> + */
> +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 1);
> +}
> +cpufreq_attr_available_freq(scaling_boost);
> +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> +
> /*
> * if you use these, you must assure that the frequency table is valid
> * all the time between get_attr and put_attr!
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 5348981..4783c4c 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -267,6 +267,10 @@ struct cpufreq_driver {
> int (*suspend) (struct cpufreq_policy *policy);
> int (*resume) (struct cpufreq_policy *policy);
> struct freq_attr **attr;
> +
> + /* platform specific boost support code */
> + bool boost_supported;
> + int (*enable_boost) (int state);
> };
>
> /* flags */
> @@ -408,6 +412,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
> #define CPUFREQ_ENTRY_INVALID ~0
> #define CPUFREQ_TABLE_END ~1
>
> +/* Define index for boost frequency */
> +#define CPUFREQ_BOOST_FREQ ~2
> +
> struct cpufreq_frequency_table {
> unsigned int index; /* any */
> unsigned int frequency; /* kHz - doesn't need to be in ascending
> @@ -426,11 +433,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
> unsigned int relation,
> unsigned int *index);
>
> +int cpufreq_boost_trigger_state(int state);
Why is this present here?
On 26 June 2013 16:24, Lukasz Majewski <[email protected]> wrote:
>> > ---
>
> So here <---> I will put change log for v5.
correct.
>> > ret = cpufreq_add_dev_interface(cpu, policy, dev);
>> > if (ret)
>
> I will add list_del(&cpufreq_policy_list);
> here.
May not be sufficient. You must do it once at the end of this routine.
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
> static unsigned int acpi_pstate_strict;
> -static bool boost_enabled, boost_supported;
> +static bool boost_enabled;
Instead of this variable use cpufreq_boost_enabled() directly.
And then this patch may change as well..
I couldn't find any more issues with this patch but some Intel guy must
review it.
On Wed, 26 Jun 2013 16:26:30 +0530, Viresh Kumar wrote:
> On 26 June 2013 16:24, Lukasz Majewski <[email protected]> wrote:
> >> > ---
> >
> > So here <---> I will put change log for v5.
>
> correct.
OK.
>
> >> > ret = cpufreq_add_dev_interface(cpu, policy, dev);
> >> > if (ret)
> >
> > I will add list_del(&cpufreq_policy_list);
> > here.
>
> May not be sufficient. You must do it once at the end of this routine.
Then I will add this code below:
err_out_kobj_put:
list_del(&cpufreq_policy_list);
[rest of error path]
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> The struct cpufreq_driver has been extended to embrace the information
> related to boost support.
>
> When "boost_mode" device tree attribute is defined for a platform, the
> low_level_boost pointer is filled with proper address. The
> .low_level_boost field filled to NULL, indicates that boost is not
> supported.
This patch is still few generations back :)
On 26 June 2013 16:34, Lukasz Majewski <[email protected]> wrote:
> err_out_kobj_put:
> list_del(&cpufreq_policy_list);
> [rest of error path]
I couldn't find err_out_kobj_put in existing code :)
BTW, just add to the list only once everything passed.
On Wed, 26 Jun 2013 16:38:15 +0530, Viresh Kumar wrote:
> On 26 June 2013 16:34, Lukasz Majewski <[email protected]> wrote:
> > err_out_kobj_put:
> > list_del(&cpufreq_policy_list);
> > [rest of error path]
>
> I couldn't find err_out_kobj_put in existing code :)
>
> BTW, just add to the list only once everything passed.
Ok, we can do it like that :-)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 26 Jun 2013 16:33:30 +0530, Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/acpi-cpufreq.c
> > b/drivers/cpufreq/acpi-cpufreq.c
>
> > static unsigned int acpi_pstate_strict;
> > -static bool boost_enabled, boost_supported;
> > +static bool boost_enabled;
>
> Instead of this variable use cpufreq_boost_enabled() directly.
OK.
>
> And then this patch may change as well..
>
> I couldn't find any more issues with this patch but some Intel guy
> must review it.
Yes, indeed Intel review is welcome.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> > Boost sysfs attribute is always exported (to support legacy API). By
> > default boost is exported as read only. One global attribute is
> > available at: /sys/devices/system/cpu/cpufreq/boost.
>
> I assume you are going to fix this as discussed in other threads.
Yes. Boost attribute will be visible only when boost is supported.
>
> > Changes for v4:
> > - Remove boost parameter from cpufreq_frequency_table_cpuinfo()
> > function
> > - Introduce cpufreq_boost_supported() method
> > - Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to
> > decide if frequency shall be skipped
> > - Rename set_boost_freq() to enable_boost()
> > - cpufreq_attr_available_freq() moved to freq_table.c
> > - Use policy list to get access to cpufreq policies
> > - Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
> > - pr_err corrected ( %sable)
> > - Remove sanity check at cpufreq_boost_trigger_state() entrance [to
> > test if boost is supported]
> > - Use either HW (boost_enable) callback or SW managed boost
> > - Introduce new cpufreq_boost_trigger_state_sw() method to handle
> > boost at SW.
> > - Protect boost_enabled manipulation with lock
> > - Always export boost attribute (preserve legacy behaviour). When
> > boost is not supported this attribute is read only
>
> Very well written changelog. But write it after ---
I will stick to the rule proposed at patch 1/4, ver 4.
>
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 665e641..9141d33 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -40,6 +40,7 @@
> > * also protects the cpufreq_cpu_data array.
> > */
> > static struct cpufreq_driver *cpufreq_driver;
> > +static bool boost_enabled;
> > static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> > #ifdef CONFIG_HOTPLUG_CPU
> > /* This one keeps track of the previously set governor of a
> > removed CPU */ @@ -316,6 +317,29 @@
> > EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /*********************************************************************
> > * SYSFS
> > INTERFACE *
> > *********************************************************************/
> > +ssize_t show_boost(struct kobject *kobj,
> > + struct attribute *attr, char *buf)
> > +{
> > + return sprintf(buf, "%d\n", boost_enabled);
> > +}
> > +
> > +static ssize_t store_boost(struct kobject *kobj, struct attribute
> > *attr,
> > + const char *buf, size_t count)
> > +{
> > + int ret, enable;
> > +
> > + ret = sscanf(buf, "%d", &enable);
> > + if (ret != 1 || enable < 0 || enable > 1)
> > + return -EINVAL;
> > +
> > + if (cpufreq_boost_trigger_state(enable)) {
> > + pr_err("%s: Cannot enable boost!\n", __func__);
> > + return -EINVAL;
> > + }
>
> Probably do boost_enabled = true here.
I would prefer to set boot_enabled at
cpufreq_boost_trigger_state() method. It is closer to the
cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
functions, which do change the freq.
>
> > + return count;
> > +}
> > +define_one_global_rw(boost);
>
> > /*********************************************************************
> > + *
> > BOOST *
> > +
> > *********************************************************************/
> > +static int cpufreq_boost_trigger_state_sw(void) +{
> > + struct cpufreq_frequency_table *freq_table;
> > + struct cpufreq_policy *policy;
> > + int ret = -EINVAL;
> > +
> > + list_for_each_entry(policy, &cpufreq_policy_list,
> > policy_list) {
> > + freq_table =
> > cpufreq_frequency_get_table(policy->cpu);
> > + if (freq_table)
> > + ret =
> > cpufreq_frequency_table_cpuinfo(policy,
> > + freq_table);
> > + }
> > +
> > + return ret;
> > +
> > +}
>
> add blank line here.
OK.
>
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (boost_enabled != state) {
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + boost_enabled = state;
> > + if (cpufreq_driver->enable_boost)
> > + ret = cpufreq_driver->enable_boost(state);
^^^^^^^^^^^^^
I would prefer to change this
name to enable_boost_hw
It is more informative, since it is tailored to hw based boost (Intel).
> > + else
> > + ret = cpufreq_boost_trigger_state_sw();
> > +
> > + if (ret) {
> > + boost_enabled = 0;
> > +
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > + pr_err("%s: BOOST cannot enable (%d)\n",
> > + __func__, ret);
> > +
> > + return ret;
> > + }
> > + write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags);
>
> You can rewrite if (ret) and unlock() code to make it less redundant.
> unlock and return ret at the end and write other stuff before it.
I will rewrite it as follow:
if (ret)
boost_enabled = 0;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
pr_debug("%s: cpufreq BOOST %s\n", __func__,
state ? "enabled" : "disabled");
return ret;
>
> > + pr_debug("%s: cpufreq BOOST %s\n", __func__,
> > + state ? "enabled" : "disabled");
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int cpufreq_boost_supported(void)
> > +{
> > + return cpufreq_driver->boost_supported;
> > +}
> > +
> > +int cpufreq_boost_enabled(void)
> > +{
> > + return boost_enabled;
> > +}
>
> EXPORT_SYMBOL_GPL ??
I will export cpufreq_boost_enabled() and cpufreq_boost_supported()
>
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + if (!cpufreq_driver->boost_supported)
> > + boost.attr.mode = 0444;
Will be removed ^^^^^^^^^^^^^^^
> > +
> > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> > + if (ret) {
> > + pr_err("%s: cannot register global boost sysfs
> > file\n",
> > + __func__);
> > + goto err_null_driver;
> > + }
>
> This would change.
This will be only exported when cpufreq_boost_supported() is true.
>
> > ret = subsys_interface_register(&cpufreq_interface);
> > if (ret)
> > goto err_null_driver;
> > @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> > subsys_interface_unregister(&cpufreq_interface);
> > +
> > + cpufreq_sysfs_remove_file(&(boost.attr));
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > list_del(&cpufreq_policy_list);
> > diff --git a/drivers/cpufreq/freq_table.c
> > b/drivers/cpufreq/freq_table.c index d7a7966..9c8e71e 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -34,6 +34,11 @@ int cpufreq_frequency_table_cpuinfo(struct
> > cpufreq_policy *policy,
> >
> > continue;
> > }
> > + if (cpufreq_boost_supported())
>
> Probably remove this check. Assume somebody while testing exynos,
> just sent boost_supported as false. Then you will not skip this
> frequency and may burn your chip :)
OK.
>
> > + if (!cpufreq_boost_enabled()
> > + && table[i].index == CPUFREQ_BOOST_FREQ)
> > + continue;
>
> This should be enough.
Let's only rely on the cpufreq_boost_enabled() test here.
>
> > pr_debug("table entry %u: %u kHz, %u index\n",
> > i, freq, table[i].index);
> > if (freq < min_freq)
> > @@ -171,7 +176,8 @@ static DEFINE_PER_CPU(struct
> > cpufreq_frequency_table *, cpufreq_show_table); /**
> > * show_available_freqs - show available frequencies for the
> > specified CPU */
> > -static ssize_t show_available_freqs(struct cpufreq_policy *policy,
> > char *buf) +static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf,
> > + int show_boost)
> > {
> > unsigned int i = 0;
> > unsigned int cpu = policy->cpu;
> > @@ -186,6 +192,9 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf) for (i = 0;
> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
>
> Add a comment here describing your complex logic.
OK.
>
> > + if (show_boost ^ (table[i].index ==
> > CPUFREQ_BOOST_FREQ))
> > + continue;
> > +
> > count += sprintf(&buf[count], "%d ",
> > table[i].frequency); }
> > count += sprintf(&buf[count], "\n");
> > @@ -194,14 +203,34 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf)
> >
> > }
> >
> > -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> > - .attr = { .name = "scaling_available_frequencies",
> > - .mode = 0444,
> > - },
> > - .show = show_available_freqs,
> > -};
> > +#define cpufreq_attr_available_freq(_name) \
> > +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
> > +__ATTR_RO(_name##_frequencies)
> > +
> > +/**
> > + * show_scaling_available_frequencies - show normal boost
> > frequencies for
>
> You missed this comment earlier. boost??
My mistake. This will be corrected.
>
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_available_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 0);
> > +}
> > +cpufreq_attr_available_freq(scaling_available);
> > EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
> >
> > +/**
> > + * show_available_boost_freqs - show available boost frequencies
> > for
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_boost_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 1);
> > +}
> > +cpufreq_attr_available_freq(scaling_boost);
> > +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> > +
> > /*
> > * if you use these, you must assure that the frequency table is
> > valid
> > * all the time between get_attr and put_attr!
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index 5348981..4783c4c 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -267,6 +267,10 @@ struct cpufreq_driver {
> > int (*suspend) (struct cpufreq_policy *policy);
> > int (*resume) (struct cpufreq_policy *policy);
> > struct freq_attr **attr;
> > +
> > + /* platform specific boost support code */
> > + bool boost_supported;
> > + int (*enable_boost) (int state);
> > };
> >
> > /* flags */
> > @@ -408,6 +412,9 @@ extern struct cpufreq_governor
> > cpufreq_gov_conservative; #define CPUFREQ_ENTRY_INVALID ~0
> > #define CPUFREQ_TABLE_END ~1
> >
> > +/* Define index for boost frequency */
> > +#define CPUFREQ_BOOST_FREQ ~2
> > +
> > struct cpufreq_frequency_table {
> > unsigned int index; /* any */
> > unsigned int frequency; /* kHz - doesn't need to be in
> > ascending @@ -426,11 +433,15 @@ int
> > cpufreq_frequency_table_target(struct cpufreq_policy *policy,
> > unsigned int relation, unsigned int *index);
> >
> > +int cpufreq_boost_trigger_state(int state);
>
> Why is this present here?
We had agreed to talk only about cpufreq :-).
This declaration will be removed.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 26 Jun 2013 16:35:32 +0530, Viresh Kumar wrote:
> On 11 June 2013 14:33, Lukasz Majewski <[email protected]> wrote:
> > The struct cpufreq_driver has been extended to embrace the
> > information related to boost support.
> >
> > When "boost_mode" device tree attribute is defined for a platform,
> > the low_level_boost pointer is filled with proper address. The
> > .low_level_boost field filled to NULL, indicates that boost is not
> > supported.
>
> This patch is still few generations back :)
But this is v2 version of boost patches.
Please also review:
[PATCH v4 4/7]
[PATCH v4 5/7]
[PATCH v4 6/7]
[PATCH v4 7/7] - disable boost at thermal framework
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 26 Jun 2013 14:54:12 +0200, Lukasz Majewski wrote:
> > >
> > > +int cpufreq_boost_trigger_state(int state);
> >
> > Why is this present here?
>
> We had agreed to talk only about cpufreq :-).
>
> This declaration will be removed.
Correction:
This declaration is needed for allowing disabling cpufreq boost at
thermal subsystem (please refer to [PATCH v4 7/7]).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 26 June 2013 19:28, Lukasz Majewski <[email protected]> wrote:
> On Wed, 26 Jun 2013 16:35:32 +0530, Viresh Kumar wrote:
>> This patch is still few generations back :)
>
> But this is v2 version of boost patches.
My mistake....
> Please also review:
> [PATCH v4 4/7]
> [PATCH v4 5/7]
> [PATCH v4 6/7]
> [PATCH v4 7/7] - disable boost at thermal framework
don't worry I will review everything. I went home after reviewing half
of the patches.
On Thu, 27 Jun 2013 09:32:56 +0530, Viresh Kumar wrote:
> On 26 June 2013 19:28, Lukasz Majewski <[email protected]> wrote:
> > On Wed, 26 Jun 2013 16:35:32 +0530, Viresh Kumar wrote:
> >> This patch is still few generations back :)
> >
> > But this is v2 version of boost patches.
>
> My mistake....
>
> > Please also review:
> > [PATCH v4 4/7]
> > [PATCH v4 5/7]
> > [PATCH v4 6/7]
> > [PATCH v4 7/7] - disable boost at thermal framework
>
> don't worry I will review everything. I went home after reviewing half
> of the patches.
Ok, Thanks.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> The struct cpufreq_driver has been extended to embrace the information
> related to boost support.
>
> When "boost_mode" device tree attribute is defined for a platform, the
> boost_supported flag is set. Moreover boost related attributes were
> exported.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> Changes for v4:
> - None
>
> Changes for v3:
> - Remove low level boost code
> - Move boost management code to cpufreq core code
> - Use boost_supported flag to indicate if driver supports over clocking
>
> Changes for v2:
> - Removal of struct cpufreq_boost
> - Removal of the CONFIG_CPU_FREQ_BOOST flag
> - low_level_boost with valid address when boost is supported
> ---
> drivers/cpufreq/exynos-cpufreq.c | 4 ++++
> 1 file changed, 4 insertions(+)
Yes, this looks fine..
I will Ack the whole series in the end, so no individual acks :)
On 26 June 2013 18:24, Lukasz Majewski <[email protected]> wrote:
> On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
>> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
>> > +static ssize_t store_boost(struct kobject *kobj, struct attribute
>> > *attr,
>> > + const char *buf, size_t count)
>> > +{
>> > + int ret, enable;
>> > +
>> > + ret = sscanf(buf, "%d", &enable);
>> > + if (ret != 1 || enable < 0 || enable > 1)
>> > + return -EINVAL;
>> > +
>> > + if (cpufreq_boost_trigger_state(enable)) {
>> > + pr_err("%s: Cannot enable boost!\n", __func__);
>> > + return -EINVAL;
>> > + }
>>
>> Probably do boost_enabled = true here.
>
> I would prefer to set boot_enabled at
> cpufreq_boost_trigger_state() method. It is closer to the
> cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
> functions, which do change the freq.
I said that as this will be more inclined towards the purpose of
this routine. This routine should store boost as show_boost()
is returning it. So, what would be better is if you just return
0 or err from cpufreq_boost_trigger_state() and then set boost
here. This will also solve your problem where you revert back
to older boost value for failure cases.
>> > + ret = cpufreq_driver->enable_boost(state);
> ^^^^^^^^^^^^^
> I would prefer to change this
> name to enable_boost_hw
> It is more informative, since it is tailored to hw based boost (Intel).
Ok
>> > + else
>> > + ret = cpufreq_boost_trigger_state_sw();
then why not enable_boost_sw() here? that would be more
relevant.
> I will rewrite it as follow:
>
> if (ret)
> boost_enabled = 0;
>
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> pr_debug("%s: cpufreq BOOST %s\n", __func__,
> state ? "enabled" : "disabled");
So, you will not print error but current state? Probably
printing error is better.
On Thu, 27 Jun 2013 14:28:11 +0530, Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> > The struct cpufreq_driver has been extended to embrace the
> > information related to boost support.
> >
> > When "boost_mode" device tree attribute is defined for a platform,
> > the boost_supported flag is set. Moreover boost related attributes
> > were exported.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > Changes for v4:
> > - None
> >
> > Changes for v3:
> > - Remove low level boost code
> > - Move boost management code to cpufreq core code
> > - Use boost_supported flag to indicate if driver supports over
> > clocking
> >
> > Changes for v2:
> > - Removal of struct cpufreq_boost
> > - Removal of the CONFIG_CPU_FREQ_BOOST flag
> > - low_level_boost with valid address when boost is supported
> > ---
> > drivers/cpufreq/exynos-cpufreq.c | 4 ++++
> > 1 file changed, 4 insertions(+)
>
> Yes, this looks fine..
>
> I will Ack the whole series in the end, so no individual acks :)
Ok.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> In the core governor code, per cpu load value is calculated. This patch
> uses it to mark processor as a "busy" one, when load value is higher than
> 90%.
How can we take this assumption. What about a cpu which is only 70-80%
busy? So, we would be running at around 70% of policy->max.. Now at
this point you want to enable boost frequency and so that will happen for
all cores... Wouldn't that burn your chip?
> New cpufreq sysfs attribute is created (busy_cpus). It is read only
> and provides information about number of actually busy CPU.
Not required.
> diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
> index 077cea7..3402533 100644
> --- a/drivers/cpufreq/cpufreq_governor.c
> +++ b/drivers/cpufreq/cpufreq_governor.c
> @@ -148,6 +148,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
> continue;
>
> load = 100 * (wall_time - idle_time) / wall_time;
> + cpufreq_set_busy_cpu(j, load > 90 ? 1 : 0);
do this only when boost is enabled.
> if (dbs_data->cdata->governor == GOV_ONDEMAND) {
> int freq_avg = __cpufreq_driver_getavg(policy, j);
On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:
> On 26 June 2013 18:24, Lukasz Majewski <[email protected]> wrote:
> > On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> >> On 19 June 2013 22:42, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > +static ssize_t store_boost(struct kobject *kobj, struct
> >> > attribute *attr,
> >> > + const char *buf, size_t count)
> >> > +{
> >> > + int ret, enable;
> >> > +
> >> > + ret = sscanf(buf, "%d", &enable);
> >> > + if (ret != 1 || enable < 0 || enable > 1)
> >> > + return -EINVAL;
> >> > +
> >> > + if (cpufreq_boost_trigger_state(enable)) {
> >> > + pr_err("%s: Cannot enable boost!\n", __func__);
> >> > + return -EINVAL;
> >> > + }
> >>
> >> Probably do boost_enabled = true here.
> >
> > I would prefer to set boot_enabled at
> > cpufreq_boost_trigger_state() method. It is closer to the
> > cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
> > functions, which do change the freq.
>
> I said that as this will be more inclined towards the purpose of
> this routine. This routine should store boost as show_boost()
> is returning it. So, what would be better is if you just return
> 0 or err from cpufreq_boost_trigger_state() and then set boost
> here. This will also solve your problem where you revert back
> to older boost value for failure cases.
I thought about this idea, but at cpufreq_boost_trigger_state_sw()
I iterate through all available policies and call
cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I use
cpufreq_boost_enabled() [**] route to search for maximal (boost)
frequency.
The [**] reads boost_enabled flag, which shall be updated before. When
this search fails, then I restore the old value of boost_enabled.
>
> >> > + ret =
> >> > cpufreq_driver->enable_boost(state);
> > ^^^^^^^^^^^^^
> > I would prefer to change
> > this name to enable_boost_hw
> > It is more informative, since it is tailored to hw based boost
> > (Intel).
>
> Ok
OK.
>
> >> > + else
> >> > + ret = cpufreq_boost_trigger_state_sw();
>
> then why not enable_boost_sw() here? that would be more
> relevant.
Could you be more specific here?
The distinction here is done on purpose:
You can either call cpufreq_driver->enable_boost for HW controlled
boost or cpufreq_boost_trigger_state_sw() for SW controlled one.
I could write:
if (cpufreq_driver->enable_boost)
ret = cpufreq_driver->enable_boost(state);
ret = cpufreq_boost_trigger_state_sw();
But then for Intel CPUs I will iterate over its policies to seek for
CPUFREQ_BOOST_FREQ marked frequencies without any purpose, since HW is
taking care of boosting.
>
> > I will rewrite it as follow:
> >
> > if (ret)
> > boost_enabled = 0;
> >
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > pr_debug("%s: cpufreq BOOST %s\n", __func__,
> > state ? "enabled" : "disabled");
>
> So, you will not print error but current state? Probably
> printing error is better.
I will change it to:
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (ret)
pr_err("%s: BOOST cannot enable (%d)\n",
__func__, ret);
return ret;
I want to avoid time consuming operations (like print) with holding
lock (and boost_enabled shall be modified under lock).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 27 June 2013 15:18, Lukasz Majewski <[email protected]> wrote:
> On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:
> I thought about this idea, but at cpufreq_boost_trigger_state_sw()
> I iterate through all available policies and call
> cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I use
> cpufreq_boost_enabled() [**] route to search for maximal (boost)
> frequency.
> The [**] reads boost_enabled flag, which shall be updated before. When
> this search fails, then I restore the old value of boost_enabled.
Ok.
>> >> > + else
>> >> > + ret = cpufreq_boost_trigger_state_sw();
>>
>> then why not enable_boost_sw() here? that would be more
>> relevant.
>
> Could you be more specific here?
I meant rename cpufreq_boost_trigger_state_sw() to
enable_boost_sw() :)
On Thu, 27 Jun 2013 15:06:43 +0530, Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <[email protected]> wrote:
> > In the core governor code, per cpu load value is calculated. This
> > patch uses it to mark processor as a "busy" one, when load value is
> > higher than 90%.
>
> How can we take this assumption. What about a cpu which is only 70-80%
> busy [*]?
Do you have any idea of how to precisely set the load threshold?
As a side note:
I've thought about this patch for some time and for me it looks like we
are mixing policy (number of busy CPUs) with abilities, which shall be
provided by the driver (boost).
Additionally, we can only roughly "estimate" [*] when boost shall run
and when it shall be turned off.
I think that, we shall leave this management [*] to the thermal
framework. This framework is designed exactly to protect from over
heating (it uses the same freq_table for passive CPU cooling) with
several trip points -> e.g. 40 deg (disable boost), 75 deg (impose max
freq as 1.0 GHz to cool down, 90 deg (shutdown immediately).
Please refer to PATH v4 7/7.
Unfortunately, since we dropped Kconfig flag for BOOST we cannot
impose "select THERMAL_FRAMEWORK", when flag for BOOST is enabled at
Kconfig.
Ideally kernel shall not even build when CONFIG_CPUFREQ_BOOST Kconfig
flag is set and thermal for target architecture is not correctly
configured (including proper trip points).
> So, we would be running at around 70% of policy->max.. Now at
> this point you want to enable boost frequency and so that will happen
> for all cores... Wouldn't that burn your chip?
As I've written above, we can only estimate here. Even with the same
manufacturer at one SoC revision BOOST will work with 95% of policy max
but the other revision will work stable only with 70%.
>
> > New cpufreq sysfs attribute is created (busy_cpus). It is read only
> > and provides information about number of actually busy CPU.
>
> Not required.
This attribute seems helpful for debug.
>
> > diff --git a/drivers/cpufreq/cpufreq_governor.c
> > b/drivers/cpufreq/cpufreq_governor.c index 077cea7..3402533 100644
> > --- a/drivers/cpufreq/cpufreq_governor.c
> > +++ b/drivers/cpufreq/cpufreq_governor.c
> > @@ -148,6 +148,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data,
> > int cpu) continue;
> >
> > load = 100 * (wall_time - idle_time) / wall_time;
> > + cpufreq_set_busy_cpu(j, load > 90 ? 1 : 0);
>
> do this only when boost is enabled.
Please read above side note.
>
> > if (dbs_data->cdata->governor == GOV_ONDEMAND) {
> > int freq_avg =
> > __cpufreq_driver_getavg(policy, j);
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thu, 27 Jun 2013 15:55:26 +0530, Viresh Kumar wrote:
> On 27 June 2013 15:18, Lukasz Majewski <[email protected]> wrote:
> > On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:
>
> > I thought about this idea, but at cpufreq_boost_trigger_state_sw()
> > I iterate through all available policies and call
> > cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I
> > use cpufreq_boost_enabled() [**] route to search for maximal (boost)
> > frequency.
> > The [**] reads boost_enabled flag, which shall be updated before.
> > When this search fails, then I restore the old value of
> > boost_enabled.
>
> Ok.
OK
>
> >> >> > + else
> >> >> > + ret =
> >> >> > cpufreq_boost_trigger_state_sw();
> >>
> >> then why not enable_boost_sw() here? that would be more
> >> relevant.
> >
> > Could you be more specific here?
>
> I meant rename cpufreq_boost_trigger_state_sw() to
> enable_boost_sw() :)
No problem:
- For SW there will be
cpufreq_boost_trigger_state_sw() renamed to enable_boost_sw()
- For HW:
cpufreq_driver->enable_boost(state) renamed to
cpufreq_driver->enable_boost_hw();
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
@Rafael: We need you to jump into this discussion now, I don't
have a good idea about what we should do :)
On 27 June 2013 16:28, Lukasz Majewski <[email protected]> wrote:
> Do you have any idea of how to precisely set the load threshold?
I thought we are talking about cpu being in idle state.
> As a side note:
>
> I've thought about this patch for some time and for me it looks like we
> are mixing policy (number of busy CPUs) with abilities, which shall be
> provided by the driver (boost).
> Additionally, we can only roughly "estimate" [*] when boost shall run
> and when it shall be turned off.
This is another problem in the patch you sent. User would simply
enable or disable boost feature from userspace only once.
Now, if you disable it at high temperatures then its responsibility
to enable it again. Which you are missing.
> I think that, we shall leave this management [*] to the thermal
> framework. This framework is designed exactly to protect from over
> heating (it uses the same freq_table for passive CPU cooling) with
> several trip points -> e.g. 40 deg (disable boost), 75 deg (impose max
> freq as 1.0 GHz to cool down, 90 deg (shutdown immediately).
> Please refer to PATH v4 7/7.
There might be platforms where overheating isn't a issue with boost,
if it is only enabled while only one cpu is in use.
> Unfortunately, since we dropped Kconfig flag for BOOST we cannot
> impose "select THERMAL_FRAMEWORK", when flag for BOOST is enabled at
> Kconfig.
Not a big deal, we can get that in if required.
> Ideally kernel shall not even build when CONFIG_CPUFREQ_BOOST Kconfig
> flag is set and thermal for target architecture is not correctly
> configured (including proper trip points).
On Thu, 27 Jun 2013 16:46:44 +0530, Viresh Kumar wrote:
> @Rafael: We need you to jump into this discussion now, I don't
> have a good idea about what we should do :)
>
> On 27 June 2013 16:28, Lukasz Majewski <[email protected]> wrote:
> > Do you have any idea of how to precisely set the load threshold?
>
> I thought we are talking about cpu being in idle state.
If we _drop_ the idea with thermal subsystem to disable the boost,
the logic as far as I've understood shall here be as follow:
Only enable BOOST when one CPU load > THRESHOLD_MAX and other CPUs <
THRESHOLD_MIN
THRESHOLD_MIN & THRESHOLD_MAX are SoC specific.
In my opinion the above constrain imposes policy to the cpufreq driver.
>
> > As a side note:
> >
> > I've thought about this patch for some time and for me it looks
> > like we are mixing policy (number of busy CPUs) with abilities,
> > which shall be provided by the driver (boost).
> > Additionally, we can only roughly "estimate" [*] when boost shall
> > run and when it shall be turned off.
>
> This is another problem in the patch you sent. User would simply
> enable or disable boost feature from userspace only once.
The above statement is definitely true for Intel. There HW manage the
frequency.
>
> Now, if you disable it at high temperatures then its responsibility
> to enable it again. Which you are missing.
So thermal or "other solution" [*] shall disable boost when overheated
and enable it back when things cool down.
[*] @ Viresh & Rafael do you have any idea about the "other solution"
here?
>
> > I think that, we shall leave this management [*] to the thermal
> > framework. This framework is designed exactly to protect from over
> > heating (it uses the same freq_table for passive CPU cooling) with
> > several trip points -> e.g. 40 deg (disable boost), 75 deg (impose
> > max freq as 1.0 GHz to cool down, 90 deg (shutdown immediately).
> > Please refer to PATH v4 7/7.
>
> There might be platforms where overheating isn't a issue with boost,
> if it is only enabled while only one cpu is in use.
Could you elaborate more on this?
I thought, that with multi core one needs to keep itself inside
power/thermal dissipation envelope.
>
> > Unfortunately, since we dropped Kconfig flag for BOOST we cannot
> > impose "select THERMAL_FRAMEWORK", when flag for BOOST is enabled at
> > Kconfig.
>
> Not a big deal, we can get that in if required.
>
> > Ideally kernel shall not even build when CONFIG_CPUFREQ_BOOST
> > Kconfig flag is set and thermal for target architecture is not
> > correctly configured (including proper trip points).
This would prevent situation when somebody made a mistake and
had enabled boost, but for some reason had forgotten to
configure/enable thermal subsystem.
Moreover Kconfig's CONFIG_CPUFREQ_BOOST flag would indicate that user
enabled boost for some reason and he/she (presumably) knows what is
doing.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (boost_enabled != state) {
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + boost_enabled = state;
> > + if (cpufreq_driver->enable_boost)
> > + ret = cpufreq_driver->enable_boost(state);
> > + else
> > + ret = cpufreq_boost_trigger_state_sw();
I will use only one call to cpufreq_driver->enable_boost(state) [*] with
either cpufreq_boost_enable_sw() (function with SW boost handling) or
the one provided by cpufreq driver.
Only when cpufreq driver doesn't provide [*], it will be filled with
"default" cpufreq_boost_enable_sw().
> > +
> > + if (ret) {
> > + boost_enabled = 0;
> > +
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > + pr_err("%s: BOOST cannot enable (%d)\n",
> > + __func__, ret);
> > +
> > + return ret;
> > + }
> > + write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags);
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 27 June 2013 21:25, Lukasz Majewski <[email protected]> wrote:
> On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
>> > + if (boost_enabled != state) {
>> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
>> > + boost_enabled = state;
>> > + if (cpufreq_driver->enable_boost)
>> > + ret = cpufreq_driver->enable_boost(state);
>> > + else
>> > + ret = cpufreq_boost_trigger_state_sw();
>
> I will use only one call to cpufreq_driver->enable_boost(state) [*] with
> either cpufreq_boost_enable_sw() (function with SW boost handling) or
> the one provided by cpufreq driver.
>
> Only when cpufreq driver doesn't provide [*], it will be filled with
> "default" cpufreq_boost_enable_sw().
I didn't get it completely. You are saying you will send a function pointer
now?
On 27 June 2013 20:12, Lukasz Majewski <[email protected]> wrote:
> On Thu, 27 Jun 2013 16:46:44 +0530, Viresh Kumar wrote:
>> @Rafael: We need you to jump into this discussion now, I don't
>> have a good idea about what we should do :)
>>
>> On 27 June 2013 16:28, Lukasz Majewski <[email protected]> wrote:
>> > Do you have any idea of how to precisely set the load threshold?
>>
>> I thought we are talking about cpu being in idle state.
>
> If we _drop_ the idea with thermal subsystem to disable the boost,
> the logic as far as I've understood shall here be as follow:
>
> Only enable BOOST when one CPU load > THRESHOLD_MAX and other CPUs <
> THRESHOLD_MIN
Again, I thought that we are talking about cpus being completely idle.
i.e. in WFI (wait for interrupt) or deeper states.
> THRESHOLD_MIN & THRESHOLD_MAX are SoC specific.
>
> In my opinion the above constrain imposes policy to the cpufreq driver.
Hmm.
> So thermal or "other solution" [*] shall disable boost when overheated
> and enable it back when things cool down.
yeah..
> [*] @ Viresh & Rafael do you have any idea about the "other solution"
> here?
Not really sure :)
>> There might be platforms where overheating isn't a issue with boost,
>> if it is only enabled while only one cpu is in use.
>
> Could you elaborate more on this?
I meant platforms where chip doesn't heat up much when only one core
is in use and is using boost frequency. So, they may not require support
for thermal layer at all.. But I am not aware of what the ground reality is. If
such systems can be possible or not.
> This would prevent situation when somebody made a mistake and
> had enabled boost, but for some reason had forgotten to
> configure/enable thermal subsystem.
>
> Moreover Kconfig's CONFIG_CPUFREQ_BOOST flag would indicate that user
> enabled boost for some reason and he/she (presumably) knows what is
> doing.
Yeah.. And drivers like ACPI cpufreq and exynos can simply do a select
from their Kconfig entries so that user isn't required to select them.
On Fri, 28 Jun 2013 09:10:53 +0530, Viresh Kumar wrote:
> On 27 June 2013 21:25, Lukasz Majewski <[email protected]> wrote:
> > On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> >> > + if (boost_enabled != state) {
> >> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> >> > + boost_enabled = state;
> >> > + if (cpufreq_driver->enable_boost)
> >> > + ret =
> >> > cpufreq_driver->enable_boost(state);
> >> > + else
> >> > + ret = cpufreq_boost_trigger_state_sw();
> >
> > I will use only one call to cpufreq_driver->enable_boost(state) [*]
> > with either cpufreq_boost_enable_sw() (function with SW boost
> > handling) or the one provided by cpufreq driver.
> >
> > Only when cpufreq driver doesn't provide [*], it will be filled with
> > "default" cpufreq_boost_enable_sw().
>
> I didn't get it completely. You are saying you will send a function
> pointer now?
No, I will use:
if (boost_enabled != state) {
write_lock_irqsave(&cpufreq_driver_lock, flags);
boost_enabled = state;
ret = cpufreq_driver->enable_boost(state);
^^^^^^^^^^^^^^^^^^^^ only one callback call
if (ret)
boost_enabled = 0;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (ret)
pr_err("%s: BOOST cannot enable (%d)\n",
__func__, ret);
}
and @ cpufreq_register_driver() I will add following line:
if (!cpufreq_driver->enable_boost)
cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
When cpufreq driver doesn't define callback for enable_boost it will be
filled with default SW cpufreq_boost_enable_sw callback.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 28 June 2013 12:19, Lukasz Majewski <[email protected]> wrote:
> No, I will use:
>
> if (boost_enabled != state) {
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> boost_enabled = state;
>
> ret = cpufreq_driver->enable_boost(state);
> ^^^^^^^^^^^^^^^^^^^^ only one callback call
> if (ret)
> boost_enabled = 0;
>
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> if (ret)
> pr_err("%s: BOOST cannot enable (%d)\n",
> __func__, ret);
> }
>
> and @ cpufreq_register_driver() I will add following line:
>
> if (!cpufreq_driver->enable_boost)
> cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
>
> When cpufreq driver doesn't define callback for enable_boost it will be
> filled with default SW cpufreq_boost_enable_sw callback.
That's some smart code. Good. :)
On Fri, 28 Jun 2013 09:20:40 +0530, Viresh Kumar wrote:
> On 27 June 2013 20:12, Lukasz Majewski <[email protected]> wrote:
> > On Thu, 27 Jun 2013 16:46:44 +0530, Viresh Kumar wrote:
> >> @Rafael: We need you to jump into this discussion now, I don't
> >> have a good idea about what we should do :)
> >>
> >> On 27 June 2013 16:28, Lukasz Majewski <[email protected]>
> >> wrote:
> >> > Do you have any idea of how to precisely set the load threshold?
> >>
> >> I thought we are talking about cpu being in idle state.
> >
> > If we _drop_ the idea with thermal subsystem to disable the boost,
> > the logic as far as I've understood shall here be as follow:
> >
> > Only enable BOOST when one CPU load > THRESHOLD_MAX and other CPUs <
> > THRESHOLD_MIN
>
> Again, I thought that we are talking about cpus being completely idle.
> i.e. in WFI (wait for interrupt) or deeper states.
>
> > THRESHOLD_MIN & THRESHOLD_MAX are SoC specific.
> >
> > In my opinion the above constrain imposes policy to the cpufreq
> > driver.
>
> Hmm.
>
> > So thermal or "other solution" [*] shall disable boost when
> > overheated and enable it back when things cool down.
>
> yeah..
For me thermal is a good candidate to enable boost again. I only need
to find a proper place for it.
>
> > [*] @ Viresh & Rafael do you have any idea about the "other
> > solution" here?
>
> Not really sure :)
Not any single one? Then I would like to propose thermal.
>
> >> There might be platforms where overheating isn't a issue with
> >> boost, if it is only enabled while only one cpu is in use.
> >
> > Could you elaborate more on this?
>
> I meant platforms where chip doesn't heat up much when only one core
> is in use and is using boost frequency. So, they may not require
> support for thermal layer at all.. But I am not aware of what the
> ground reality is. If such systems can be possible or not.
Ok.
>
> > This would prevent situation when somebody made a mistake and
> > had enabled boost, but for some reason had forgotten to
> > configure/enable thermal subsystem.
> >
> > Moreover Kconfig's CONFIG_CPUFREQ_BOOST flag would indicate that
> > user enabled boost for some reason and he/she (presumably) knows
> > what is doing.
>
> Yeah.. And drivers like ACPI cpufreq and exynos can simply do a select
> from their Kconfig entries so that user isn't required to select them.
Automatic select is not a good option. My goal would be here to define
BOOST as NO by default (at lease for SW managed ones). And allow user
to enable it explicitly.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 28 Jun 2013 12:21:21 +0530, Viresh Kumar wrote:
> On 28 June 2013 12:19, Lukasz Majewski <[email protected]> wrote:
> > No, I will use:
> >
> > if (boost_enabled != state) {
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > boost_enabled = state;
> >
> > ret = cpufreq_driver->enable_boost(state);
> > ^^^^^^^^^^^^^^^^^^^^ only one callback call
> > if (ret)
> > boost_enabled = 0;
> >
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > if (ret)
> > pr_err("%s: BOOST cannot enable (%d)\n",
> > __func__, ret);
> > }
> >
> > and @ cpufreq_register_driver() I will add following line:
> >
> > if (!cpufreq_driver->enable_boost)
> > cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
> >
> > When cpufreq driver doesn't define callback for enable_boost it
> > will be filled with default SW cpufreq_boost_enable_sw callback.
>
> That's some smart code. Good. :)
OK
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 28 Jun 2013 08:54:57 +0200, Lukasz Majewski wrote:
> > > So thermal or "other solution" [*] shall disable boost when
> > > overheated and enable it back when things cool down.
> >
> > yeah..
>
> For me thermal is a good candidate to enable boost again. I only need
> to find a proper place for it.
Unfortunately, after careful investigation it turned out, that thermal
is suited to disable boost when overheating is detected. (since it uses
thermal subsystem interrupt to take action).
The problem is with enabling boost again, since thermal (at least at my
board) only reacts on TMU (thermal) interrupt. Thermal thread may be
started, but I don't regard this as a good solution (to extra bloat
thermal).
>
> >
> > > [*] @ Viresh & Rafael do you have any idea about the "other
> > > solution" here?
> >
> > Not really sure :)
>
> Not any single one? Then I would like to propose thermal.
>
Does anybody have any idea here? As written above, thermal is suitable
to disable boost.
I'd like to bring those three options under discussion:
1. boost attr is always exported -> do not enable boost automatically
when disabled by thermal (as it was proposed at v4).
2. boost attr is always exported -> find a way to enable boost after
emergency disablement when thermal detects overheating (newest
proposition).
3. boost attr only exported at x86 (when supported)
boost attr NOT exported via sysfs for SW controlled boost (e.g.
Exynos ARM).
Then we only enable/disable boost at kernel and don't need to take
care of the user space interaction. This scenario is my use case. I
hadn't planned to expose boost to userspace and use it with LAB as a
kernel API.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Hi Lukasz,
Sorry for being late. Actually I didn't had an answer to your mail
and wanted to go through it with some fresh mind. This is my
first mail this morning, lets see if I can bring something good
into the discussion.
On 1 July 2013 13:45, Lukasz Majewski <[email protected]> wrote:
> Does anybody have any idea here? As written above, thermal is suitable
> to disable boost.
See, one thing is very clear. User space applications aren't responsible
for enabling boost again and again. There has to be a internal mechanism
inside kernel for that.
> I'd like to bring those three options under discussion:
>
> 1. boost attr is always exported -> do not enable boost automatically
> when disabled by thermal (as it was proposed at v4).
So, that's a problem. I see one more solution to that.
- Create another Macro in cpufreq.c which would contain the time
after which we will autoenable boost.
- So, suppose thermal disabled it due to high temperature (Lets not
change value of sysfs variable boost_enable, but create another
variable like: skip_boost: which means skip boost temporarily).
- Thermal would enable this variable skip_boost.
- Then we will continue to get requests for next frequency and will
check eveytime if we have exceeded time for autoenabling boost.
- If yes, then we disable this variable and start boosting again..
- Then thermal can disable it again later.
This variable (time for autoenable) looks to be more platform
dependent for now, but lets don't make it like that unless somebody
needs it.
> 2. boost attr is always exported -> find a way to enable boost after
> emergency disablement when thermal detects overheating (newest
> proposition).
My solution above probably.
> 3. boost attr only exported at x86 (when supported)
> boost attr NOT exported via sysfs for SW controlled boost (e.g.
> Exynos ARM).
>
> Then we only enable/disable boost at kernel and don't need to take
> care of the user space interaction. This scenario is my use case. I
> hadn't planned to expose boost to userspace and use it with LAB as a
> kernel API.
Userspace must have control of this feature after kernel is built. That kernel
image may run for ever without changing in a product.
@Rafael: How crazy do you think my solution is? :)
On Thu, 04 Jul 2013 10:36:53 +0530, Viresh Kumar wrote:
> Hi Lukasz,
>
> Sorry for being late. Actually I didn't had an answer to your mail
> and wanted to go through it with some fresh mind. This is my
> first mail this morning, lets see if I can bring something good
> into the discussion.
>
> On 1 July 2013 13:45, Lukasz Majewski <[email protected]> wrote:
> > Does anybody have any idea here? As written above, thermal is
> > suitable to disable boost.
>
> See, one thing is very clear. User space applications aren't
> responsible for enabling boost again and again. There has to be a
> internal mechanism inside kernel for that.
>
> > I'd like to bring those three options under discussion:
> >
> > 1. boost attr is always exported -> do not enable boost
> > automatically when disabled by thermal (as it was proposed at v4).
>
> So, that's a problem. I see one more solution to that.
> - Create another Macro in cpufreq.c which would contain the time
> after which we will autoenable boost.
> - So, suppose thermal disabled it due to high temperature (Lets not
> change value of sysfs variable boost_enable, but create another
> variable like: skip_boost: which means skip boost temporarily).
> - Thermal would enable this variable skip_boost.
> - Then we will continue to get requests for next frequency and will
> check eveytime if we have exceeded time for autoenabling boost.
> - If yes, then we disable this variable and start boosting again..
> - Then thermal can disable it again later.
>
> This variable (time for autoenable) looks to be more platform
> dependent for now, but lets don't make it like that unless somebody
> needs it.
>
> > 2. boost attr is always exported -> find a way to enable boost after
> > emergency disablement when thermal detects overheating (newest
> > proposition).
>
> My solution above probably.
This is a possible solution, but I've already modified thermal code a
bit and found a solution for the problem.
I use thermal workqueue (which is already in place anyway) to enable the
boost again.
Due to that I can provide behaviour similar to HW controlled boost.
Patches with this solution are already prepared. I will post them in a
few hours. Ok?
>
> > 3. boost attr only exported at x86 (when supported)
> > boost attr NOT exported via sysfs for SW controlled boost (e.g.
> > Exynos ARM).
> >
> > Then we only enable/disable boost at kernel and don't need to
> > take care of the user space interaction. This scenario is my use
> > case. I hadn't planned to expose boost to userspace and use it with
> > LAB as a kernel API.
>
> Userspace must have control of this feature after kernel is built.
> That kernel image may run for ever without changing in a product.
>
> @Rafael: How crazy do you think my solution is? :)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 4 July 2013 11:13, Lukasz Majewski <[email protected]> wrote:
> This is a possible solution, but I've already modified thermal code a
> bit and found a solution for the problem.
>
> I use thermal workqueue (which is already in place anyway) to enable the
> boost again.
> Due to that I can provide behaviour similar to HW controlled boost.
>
> Patches with this solution are already prepared. I will post them in a
> few hours. Ok?
I don't see any harm in checking them out :)
Please send them.
On Thu, 04 Jul 2013 11:58:53 +0530, Viresh Kumar wrote:
> On 4 July 2013 11:13, Lukasz Majewski <[email protected]> wrote:
> > This is a possible solution, but I've already modified thermal code
> > a bit and found a solution for the problem.
> >
> > I use thermal workqueue (which is already in place anyway) to
> > enable the boost again.
> > Due to that I can provide behaviour similar to HW controlled boost.
> >
> > Patches with this solution are already prepared. I will post them
> > in a few hours. Ok?
>
> I don't see any harm in checking them out :)
> Please send them.
:-)
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing enable_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selectable only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- enable_boost - callback to function, which is necessary to
enable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- All available policies are now stored in a list.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring of target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
New patches for v5:
cpufreq:boost:Kconfig: Enable software managed BOOST support at Kconfig
Documentation:cpufreq:boost: Update BOOST documentation
Patches dropped at v5:
cpufreq: Calculate number of busy CPUs
cpufreq: Enable software boost only when up to one busy core is running
Tested at: HW:
Exynos 4412 3.10 linux
Exynos 4210 3.10 linux
Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem) test
needed
The code has been rebased on top of kernel_pm/bleeding-edge (3.11-rc1)
Lukasz Majewski (7):
cpufreq: Store cpufreq policies in a list
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Enable software managed BOOST support at
Kconfig
Documentation:cpufreq:boost: Update BOOST documentation
Documentation/cpu-freq/boost.txt | 26 ++++-----
drivers/cpufreq/Kconfig | 14 +++++
drivers/cpufreq/acpi-cpufreq.c | 69 +++++++----------------
drivers/cpufreq/cpufreq.c | 115 ++++++++++++++++++++++++++++++++++++++
drivers/cpufreq/exynos-cpufreq.c | 9 ++-
drivers/cpufreq/freq_table.c | 47 +++++++++++++---
drivers/thermal/thermal_core.c | 31 ++++++++++
include/linux/cpufreq.h | 13 +++++
include/linux/thermal.h | 2 +
9 files changed, 257 insertions(+), 69 deletions(-)
--
1.7.10.4
Policies available in a cpufreq framework are now linked together. They are
accessible via cpufreq_policy_list defined at cpufreq core.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- Call list_add() only when device successfully added
Changes for v4:
- New patch
drivers/cpufreq/cpufreq.c | 3 +++
include/linux/cpufreq.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0937b8d..420ccb5 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -46,6 +46,7 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock);
+static LIST_HEAD(cpufreq_policy_list);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -1054,6 +1055,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
if (ret)
goto err_out_unregister;
+ list_add(&policy->policy_list, &cpufreq_policy_list);
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
pr_debug("initialization complete\n");
@@ -2056,6 +2058,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
subsys_interface_unregister(&cpufreq_interface);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
+ list_del(&cpufreq_policy_list);
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 90d5a15..d8e30fc 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -117,6 +117,7 @@ struct cpufreq_policy {
struct cpufreq_real_policy user_policy;
+ struct list_head policy_list;
struct kobject kobj;
struct completion kobj_unregister;
int transition_ongoing; /* Tracks transition status */
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 31 +++++++++++++++++++++++++++++++
include/linux/thermal.h | 2 ++
2 files changed, 33 insertions(+)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index d755440..12adbad 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -33,6 +33,7 @@
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/reboot.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
static void handle_non_critical_trips(struct thermal_zone_device *tz,
int trip, enum thermal_trip_type trip_type)
{
+ if (cpufreq_boost_supported()) {
+ tz->overheated = true;
+ cpufreq_boost_trigger_state(0);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ }
+
if (tz->governor)
tz->governor->throttle(tz, trip);
}
@@ -453,6 +463,27 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ long trip_temp;
+
+ if (cpufreq_boost_supported() && tz->overheated) {
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ monitor_thermal_zone(tz);
+ }
+
+ cpufreq_boost_trigger_state(1);
+ return;
+ }
+ }
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1c..f1aa3c2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "CPU frequency BOOST support" Kconfig option the
software managed boost is enabled. It also selects thermal subsystem
to be compiled in. Thermal is necessary for disabling boost and cooling
down the device when overheating detected.
Boost _MUST_NOT_ be enabled without thermal subsystem with properly
defined temperatures, which indicate overheating.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 14 ++++++++++++++
drivers/cpufreq/exynos-cpufreq.c | 5 ++++-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 534fcb8..e65a112 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,20 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool "CPU frequency overclocking (BOOST)"
+ depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
+ default n
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for a particular processor
+ if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly defined
+ trip points.
+
+ If in doubt, say N.
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 4f42fcc..7586b28 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -288,7 +288,9 @@ static struct cpufreq_driver exynos_driver = {
static int __init exynos_cpufreq_init(void)
{
+#ifdef CONFIG_CPU_FREQ_BOOST_SW
struct device_node *node = pdev->dev.of_node;
+#endif
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -319,9 +321,10 @@ static int __init exynos_cpufreq_init(void)
}
locking_frequency = exynos_getspeed(0);
+#ifdef CONFIG_CPU_FREQ_BOOST_SW
if (of_property_read_bool(node, "boost_mode"))
exynos_driver.boost_supported = 1;
-
+#endif
register_pm_notifier(&exynos_cpufreq_nb);
if (cpufreq_register_driver(&exynos_driver)) {
--
1.7.10.4
The struct cpufreq_driver has been extended to embrace the information
related to boost support.
When "boost_mode" device tree attribute is defined for a platform, the
boost_supported flag is set. Moreover boost related attributes were
exported.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 0d32f02..4f42fcc 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -267,6 +267,7 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_scaling_boost_freqs,
NULL,
};
@@ -287,6 +288,7 @@ static struct cpufreq_driver exynos_driver = {
static int __init exynos_cpufreq_init(void)
{
+ struct device_node *node = pdev->dev.of_node;
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
@@ -317,6 +319,8 @@ static int __init exynos_cpufreq_init(void)
}
locking_frequency = exynos_getspeed(0);
+ if (of_property_read_bool(node, "boost_mode"))
+ exynos_driver.boost_supported = 1;
register_pm_notifier(&exynos_cpufreq_nb);
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost_freq
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 69 ++++++++++++----------------------------
1 file changed, 21 insertions(+), 48 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 3926402..113a928 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -81,7 +81,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -134,49 +133,33 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
+{
+ get_online_cpus();
+ boost_set_msrs(val, cpu_online_mask);
+ put_online_cpus();
+ pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
+
+ return 0;
+}
+
+static ssize_t store_boost(const char *buf, size_t count)
{
int ret;
unsigned long val = 0;
- if (!boost_supported)
+ if (!acpi_cpufreq_driver.boost_supported)
return -EINVAL;
ret = kstrtoul(buf, 10, &val);
if (ret || (val > 1))
return -EINVAL;
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
- get_online_cpus();
-
- boost_set_msrs(val, cpu_online_mask);
-
- put_online_cpus();
-
- boost_enabled = val;
- pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
+ _store_boost((int) val);
return count;
}
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
-}
-
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -190,12 +173,12 @@ cpufreq_freq_attr_ro(freqdomain_cpus);
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", cpufreq_boost_enabled());
}
static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
@@ -583,7 +566,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(cpufreq_boost_enabled(), cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -943,6 +926,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
+ .enable_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -953,33 +937,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
+ cpufreq_set_boost_enabled(boost_state(0));
+ acpi_cpufreq_driver.boost_supported = true;
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(cpufreq_boost_enabled(), cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software).
Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
its normal operation limits. Such a mode shall be only used for a short
time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) over clocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code.
By default boost is disabled. One global attribute is available at:
/sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with proper call to
sysfs.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 112 ++++++++++++++++++++++++++++++++++++++++++
drivers/cpufreq/freq_table.c | 47 +++++++++++++++---
include/linux/cpufreq.h | 12 +++++
3 files changed, 164 insertions(+), 7 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 420ccb5..531189f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -43,6 +43,7 @@
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver;
+static bool boost_enabled;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock);
@@ -377,6 +378,32 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot enable boost!\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -1963,6 +1990,72 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_enable_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (!ret)
+ policy->user_policy.max = policy->max;
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (boost_enabled != state) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ boost_enabled = state;
+
+ ret = cpufreq_driver->enable_boost(state);
+ if (ret)
+ boost_enabled = 0;
+
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ if (ret)
+ pr_err("%s: BOOST cannot enable (%d)\n",
+ __func__, ret);
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (cpufreq_driver)
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+void cpufreq_set_boost_enabled(int state)
+{
+ boost_enabled = state;
+}
+EXPORT_SYMBOL_GPL(cpufreq_set_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2001,6 +2094,22 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_driver->boost_supported) {
+ /*
+ * Check if boost driver provides function to enable boost -
+ * if not, use cpufreq_boost_enable_sw as default
+ */
+ if (!cpufreq_driver->enable_boost)
+ cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
+
+ ret = cpufreq_sysfs_create_file(&(boost.attr));
+ if (ret) {
+ pr_err("%s: cannot register global boost sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
goto err_null_driver;
@@ -2056,6 +2165,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_driver->boost_supported)
+ cpufreq_sysfs_remove_file(&(boost.attr));
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
list_del(&cpufreq_policy_list);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f0d8741..490518f 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,6 +34,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -171,7 +174,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ int show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,6 +190,15 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq ->
+ * display BOOST
+ * show_boost = false and driver_data = BOOST freq -> continue
+ * and display only non BOOST frequencies
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -194,14 +207,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 0);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 1);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d8e30fc..3b50688 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -267,6 +267,10 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ int (*enable_boost) (int state);
};
/* flags */
@@ -411,6 +415,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST_FREQ ~2
+
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
unsigned int frequency; /* kHz - doesn't need to be in ascending
@@ -429,11 +436,16 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+int cpufreq_boost_trigger_state(int state);
+void cpufreq_set_boost_enabled(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
On Thursday, July 04, 2013 10:36:53 AM Viresh Kumar wrote:
> Hi Lukasz,
>
> Sorry for being late. Actually I didn't had an answer to your mail
> and wanted to go through it with some fresh mind. This is my
> first mail this morning, lets see if I can bring something good
> into the discussion.
>
> On 1 July 2013 13:45, Lukasz Majewski <[email protected]> wrote:
> > Does anybody have any idea here? As written above, thermal is suitable
> > to disable boost.
>
> See, one thing is very clear. User space applications aren't responsible
> for enabling boost again and again. There has to be a internal mechanism
> inside kernel for that.
>
> > I'd like to bring those three options under discussion:
> >
> > 1. boost attr is always exported -> do not enable boost automatically
> > when disabled by thermal (as it was proposed at v4).
>
> So, that's a problem. I see one more solution to that.
> - Create another Macro in cpufreq.c which would contain the time
> after which we will autoenable boost.
Well, how can we tell what time is correct here? It may depend on factors not
under our control or even variable, like the ambient temperature, so surely
it might not be a hard coded value.
> - So, suppose thermal disabled it due to high temperature (Lets not
> change value of sysfs variable boost_enable, but create another
> variable like: skip_boost: which means skip boost temporarily).
What about "block_boost"? Other than that, this particular item is a good idea
I think.
> - Thermal would enable this variable skip_boost.
> - Then we will continue to get requests for next frequency and will
> check eveytime if we have exceeded time for autoenabling boost.
> - If yes, then we disable this variable and start boosting again..
I wonder if we could use thermal watermarks instead? Such that a high
watermark would cause block_boost to be set and a low watermark would cause
it to be reset? And the thermal layer would be in control of both watermarks?
> - Then thermal can disable it again later.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Hi Lukasz,
> -----Original Message-----
> From: [email protected] [mailto:linux-pm-
> [email protected]] On Behalf Of Lukasz Majewski
> Sent: Thursday, July 04, 2013 2:20 PM
> To: Viresh Kumar; Rafael J. Wysocki; Zhang, Rui; Eduardo Valentin
> Cc: [email protected]; Linux PM list; Jonghwa Lee; Lukasz Majewski;
> [email protected]; linux-kernel; Andre Przywara; Daniel Lezcano; Kukjin Kim;
> Myungjoo Ham
> Subject: [PATCH v5 5/7] thermal:boost: Automatic enable/disable of BOOST
> feature
>
> This patch provides auto disable/enable operation for boost. When any
> defined trip point is passed, the boost is disabled.
> In that moment thermal monitor workqueue is woken up and it monitors
> if the device temperature drops below 75% of the smallest trip point.
> When device cools down, the boost is enabled again.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v5:
> - Move boost disable code from cpu_cooling.c to thermal_core.c
> (to handle_non_critical_trips)
> - Extent struct thermal_zone_device by adding overheated bool flag
> - Implement auto enable of boost after device cools down
> - Introduce boost_polling flag, which indicates if thermal uses it's predefined
> pool delay or has woken up thermal workqueue only to wait until device
> cools down.
>
> Changes for v4:
> - New patch
>
> drivers/thermal/thermal_core.c | 31 +++++++++++++++++++++++++++++++
> include/linux/thermal.h | 2 ++
> 2 files changed, 33 insertions(+)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index d755440..12adbad 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -33,6 +33,7 @@
> #include <linux/idr.h>
> #include <linux/thermal.h>
> #include <linux/reboot.h>
> +#include <linux/cpufreq.h>
> #include <net/netlink.h>
> #include <net/genetlink.h>
>
> @@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct
> thermal_zone_device *tz)
> static void handle_non_critical_trips(struct thermal_zone_device *tz,
> int trip, enum thermal_trip_type trip_type)
> {
> + if (cpufreq_boost_supported()) {
> + tz->overheated = true;
> + cpufreq_boost_trigger_state(0);
> + if (!tz->polling_delay) {
> + tz->boost_polling = true;
> + tz->polling_delay = 1000;
> + }
> + }
> +
> if (tz->governor)
> tz->governor->throttle(tz, trip);
> }
> @@ -453,6 +463,27 @@ static void thermal_zone_device_check(struct
> work_struct *work)
> struct thermal_zone_device *tz = container_of(work, struct
> thermal_zone_device,
> poll_queue.work);
> + long trip_temp;
> +
> + if (cpufreq_boost_supported() && tz->overheated) {
Not all thermal drivers support trip points. So, we first need a
if (tz->ops->get_trip_temp) check here.
> + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> + /*
> + * Enable boost again only when current temperature is less
> + * than 75% of trip_temp[0]
> + */
> + if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
Another way would be to use the get_trend APIs for this thermal zone.
If the trend is cooling we can re-enable boost otherwise not.
> + tz->overheated = false;
> + if (tz->boost_polling) {
> + tz->boost_polling = false;
> + tz->polling_delay = 0;
> + monitor_thermal_zone(tz);
> + }
Overall, I believe this will work well only if the thermal zone is CPU.
Another suggestion is: We tried hard to remove all throttling logic from
thermal_core.c. May be we should include this kind of logic in
step_wise.c ? Rui/Eduardo: Any thoughts on this ?
Thanks,
Durga
> +
> + cpufreq_boost_trigger_state(1);
> + return;
> + }
> + }
> +
> thermal_zone_device_update(tz);
> }
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index a386a1c..f1aa3c2 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -172,6 +172,8 @@ struct thermal_zone_device {
> int emul_temperature;
> int passive;
> unsigned int forced_passive;
> + bool overheated;
> + bool boost_polling;
> const struct thermal_zone_device_ops *ops;
> const struct thermal_zone_params *tzp;
> struct thermal_governor *governor;
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, 4 Jul 2013 17:19:04 +0000
"R, Durgadoss" <[email protected]> wrote:
Hi,
> Hi Lukasz,
>
> > -----Original Message-----
> > From: [email protected] [mailto:linux-pm-
> > [email protected]] On Behalf Of Lukasz Majewski
> > Sent: Thursday, July 04, 2013 2:20 PM
> > To: Viresh Kumar; Rafael J. Wysocki; Zhang, Rui; Eduardo Valentin
> > Cc: [email protected]; Linux PM list; Jonghwa Lee; Lukasz
> > Majewski; [email protected]; linux-kernel; Andre Przywara;
> > Daniel Lezcano; Kukjin Kim; Myungjoo Ham
> > Subject: [PATCH v5 5/7] thermal:boost: Automatic enable/disable of
> > BOOST feature
> >
> > This patch provides auto disable/enable operation for boost. When
> > any defined trip point is passed, the boost is disabled.
> > In that moment thermal monitor workqueue is woken up and it monitors
> > if the device temperature drops below 75% of the smallest trip
> > point. When device cools down, the boost is enabled again.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > ---
> > Changes for v5:
> > - Move boost disable code from cpu_cooling.c to thermal_core.c
> > (to handle_non_critical_trips)
> > - Extent struct thermal_zone_device by adding overheated bool flag
> > - Implement auto enable of boost after device cools down
> > - Introduce boost_polling flag, which indicates if thermal uses
> > it's predefined pool delay or has woken up thermal workqueue only
> > to wait until device cools down.
> >
> > Changes for v4:
> > - New patch
> >
> > drivers/thermal/thermal_core.c | 31
> > +++++++++++++++++++++++++++++++ include/linux/thermal.h |
> > 2 ++ 2 files changed, 33 insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c index d755440..12adbad 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -33,6 +33,7 @@
> > #include <linux/idr.h>
> > #include <linux/thermal.h>
> > #include <linux/reboot.h>
> > +#include <linux/cpufreq.h>
> > #include <net/netlink.h>
> > #include <net/genetlink.h>
> >
> > @@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct
> > thermal_zone_device *tz)
> > static void handle_non_critical_trips(struct thermal_zone_device
> > *tz, int trip, enum thermal_trip_type trip_type)
> > {
> > + if (cpufreq_boost_supported()) {
> > + tz->overheated = true;
> > + cpufreq_boost_trigger_state(0);
> > + if (!tz->polling_delay) {
> > + tz->boost_polling = true;
> > + tz->polling_delay = 1000;
> > + }
> > + }
> > +
> > if (tz->governor)
> > tz->governor->throttle(tz, trip);
> > }
> > @@ -453,6 +463,27 @@ static void thermal_zone_device_check(struct
> > work_struct *work)
> > struct thermal_zone_device *tz = container_of(work, struct
> > thermal_zone_device,
> > poll_queue.work);
> > + long trip_temp;
> > +
> > + if (cpufreq_boost_supported() && tz->overheated) {
>
> Not all thermal drivers support trip points. So, we first need a
> if (tz->ops->get_trip_temp) check here.
Ok, thanks for tip. Bluntly speaking, I thought, that all SoCs supported
by thermal set trip points.
>
> > + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> > + /*
> > + * Enable boost again only when current
> > temperature is less
> > + * than 75% of trip_temp[0]
> > + */
> > + if ((tz->temperature + (trip_temp >> 2)) <
> > trip_temp) {
>
> Another way would be to use the get_trend APIs for this thermal zone.
> If the trend is cooling we can re-enable boost otherwise not.
Trend evaluation seems like a good complementary idea.
However, I would also like to have the relative temperature drop
measurement (if possible) like above (to 75% of the first trip point).
Then I would be more confident, that everything cooled down and that I
can start boost again.
>
> > + tz->overheated = false;
> > + if (tz->boost_polling) {
> > + tz->boost_polling = false;
> > + tz->polling_delay = 0;
> > + monitor_thermal_zone(tz);
> > + }
>
> Overall, I believe this will work well only if the thermal zone is
> CPU.
My assumption:
When I enable boost at CPU, then I also shall cool down the CPU. And
the CPU zone seemed a natural choice.
However I might be missing something, so hints are welcome.
>
> Another suggestion is: We tried hard to remove all throttling logic
> from thermal_core.c.
By throttling logic you mean:
if ((tz->temperature + (trip_temp >> 2)) and other conditions (like
trend measurement)?
> May be we should include this kind of logic in
> step_wise.c ?
It sounds interesting (since ->throttle at thermal_core.c is called
always when needed), but I'm afraid of a code duplication when one
use Boost with fair_share or other thermal governor.
> Rui/Eduardo: Any thoughts on this ?
>
> Thanks,
> Durga
> > +
> > + cpufreq_boost_trigger_state(1);
> > + return;
> > + }
> > + }
> > +
> > thermal_zone_device_update(tz);
> > }
> >
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index a386a1c..f1aa3c2 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -172,6 +172,8 @@ struct thermal_zone_device {
> > int emul_temperature;
> > int passive;
> > unsigned int forced_passive;
> > + bool overheated;
> > + bool boost_polling;
> > const struct thermal_zone_device_ops *ops;
> > const struct thermal_zone_params *tzp;
> > struct thermal_governor *governor;
> > --
> > 1.7.10.4
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pm"
> > in the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Lukasz,
> -----Original Message-----
> From: Lukasz Majewski [mailto:[email protected]]
> Sent: Friday, July 05, 2013 2:28 AM
> To: R, Durgadoss
> Cc: Lukasz Majewski; Viresh Kumar; Rafael J. Wysocki; Zhang, Rui; Eduardo
> Valentin; [email protected]; Linux PM list; Jonghwa Lee; linux-kernel;
> Andre Przywara; Daniel Lezcano; Kukjin Kim; Myungjoo Ham
> Subject: Re: [PATCH v5 5/7] thermal:boost: Automatic enable/disable of BOOST
> feature
>
> On Thu, 4 Jul 2013 17:19:04 +0000
> "R, Durgadoss" <[email protected]> wrote:
> Hi,
>
[Cut.]
> > > @@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct
> > > thermal_zone_device *tz)
> > > static void handle_non_critical_trips(struct thermal_zone_device
> > > *tz, int trip, enum thermal_trip_type trip_type)
> > > {
> > > + if (cpufreq_boost_supported()) {
> > > + tz->overheated = true;
> > > + cpufreq_boost_trigger_state(0);
> > > + if (!tz->polling_delay) {
> > > + tz->boost_polling = true;
> > > + tz->polling_delay = 1000;
> > > + }
> > > + }
> > > +
> > > if (tz->governor)
> > > tz->governor->throttle(tz, trip);
> > > }
> > > @@ -453,6 +463,27 @@ static void thermal_zone_device_check(struct
> > > work_struct *work)
> > > struct thermal_zone_device *tz = container_of(work, struct
> > > thermal_zone_device,
> > > poll_queue.work);
> > > + long trip_temp;
> > > +
> > > + if (cpufreq_boost_supported() && tz->overheated) {
> >
> > Not all thermal drivers support trip points. So, we first need a
> > if (tz->ops->get_trip_temp) check here.
>
> Ok, thanks for tip. Bluntly speaking, I thought, that all SoCs supported
> by thermal set trip points.
We would wish to get there. But not the reality today ;)
>
> >
> > > + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> > > + /*
> > > + * Enable boost again only when current
> > > temperature is less
> > > + * than 75% of trip_temp[0]
> > > + */
> > > + if ((tz->temperature + (trip_temp >> 2)) <
> > > trip_temp) {
> >
> > Another way would be to use the get_trend APIs for this thermal zone.
> > If the trend is cooling we can re-enable boost otherwise not.
>
> Trend evaluation seems like a good complementary idea.
>
> However, I would also like to have the relative temperature drop
> measurement (if possible) like above (to 75% of the first trip point).
>
> Then I would be more confident, that everything cooled down and that I
> can start boost again.
>
> >
> > > + tz->overheated = false;
> > > + if (tz->boost_polling) {
> > > + tz->boost_polling = false;
> > > + tz->polling_delay = 0;
> > > + monitor_thermal_zone(tz);
> > > + }
> >
> > Overall, I believe this will work well only if the thermal zone is
> > CPU.
>
> My assumption:
>
> When I enable boost at CPU, then I also shall cool down the CPU. And
> the CPU zone seemed a natural choice.
>
> However I might be missing something, so hints are welcome.
>
> >
> > Another suggestion is: We tried hard to remove all throttling logic
> > from thermal_core.c.
>
> By throttling logic you mean:
> if ((tz->temperature + (trip_temp >> 2)) and other conditions (like
> trend measurement)?
Yes. That is correct.
>
> > May be we should include this kind of logic in
> > step_wise.c ?
>
> It sounds interesting (since ->throttle at thermal_core.c is called
> always when needed), but I'm afraid of a code duplication when one
> use Boost with fair_share or other thermal governor.
right. So, for the time being, (as part of this patch series)
I am Okay to have this code in thermal_core.c. From the thermal
subsystem perspective, we will (need to) work out a better/
cleaner/easier approach for this later.
Thanks,
Durga
On Fri, 05 Jul 2013 05:31:42 +0000, R, Durgadoss wrote:
Hi Durga,
> Hi Lukasz,
>
> > -----Original Message-----
> > From: Lukasz Majewski [mailto:[email protected]]
> > Sent: Friday, July 05, 2013 2:28 AM
> > To: R, Durgadoss
> > Cc: Lukasz Majewski; Viresh Kumar; Rafael J. Wysocki; Zhang, Rui;
> > Eduardo Valentin; [email protected]; Linux PM list; Jonghwa
> > Lee; linux-kernel; Andre Przywara; Daniel Lezcano; Kukjin Kim;
> > Myungjoo Ham Subject: Re: [PATCH v5 5/7] thermal:boost: Automatic
> > enable/disable of BOOST feature
> >
> > On Thu, 4 Jul 2013 17:19:04 +0000
> > "R, Durgadoss" <[email protected]> wrote:
> > Hi,
> >
>
> [Cut.]
>
> > > > @@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct
> > > > thermal_zone_device *tz)
> > > > static void handle_non_critical_trips(struct
> > > > thermal_zone_device *tz, int trip, enum thermal_trip_type
> > > > trip_type) {
> > > > + if (cpufreq_boost_supported()) {
> > > > + tz->overheated = true;
> > > > + cpufreq_boost_trigger_state(0);
> > > > + if (!tz->polling_delay) {
> > > > + tz->boost_polling = true;
> > > > + tz->polling_delay = 1000;
> > > > + }
> > > > + }
> > > > +
> > > > if (tz->governor)
> > > > tz->governor->throttle(tz, trip);
> > > > }
> > > > @@ -453,6 +463,27 @@ static void
> > > > thermal_zone_device_check(struct work_struct *work)
> > > > struct thermal_zone_device *tz = container_of(work,
> > > > struct thermal_zone_device,
> > > > poll_queue.work);
> > > > + long trip_temp;
> > > > +
> > > > + if (cpufreq_boost_supported() && tz->overheated) {
> > >
> > > Not all thermal drivers support trip points. So, we first need a
> > > if (tz->ops->get_trip_temp) check here.
> >
> > Ok, thanks for tip. Bluntly speaking, I thought, that all SoCs
> > supported by thermal set trip points.
>
> We would wish to get there. But not the reality today ;)
Ok, I see :-).
>
> >
> > >
> > > > + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> > > > + /*
> > > > + * Enable boost again only when current
> > > > temperature is less
> > > > + * than 75% of trip_temp[0]
> > > > + */
> > > > + if ((tz->temperature + (trip_temp >> 2)) <
> > > > trip_temp) {
> > >
> > > Another way would be to use the get_trend APIs for this thermal
> > > zone. If the trend is cooling we can re-enable boost otherwise
> > > not.
> >
> > Trend evaluation seems like a good complementary idea.
> >
> > However, I would also like to have the relative temperature drop
> > measurement (if possible) like above (to 75% of the first trip
> > point).
> >
> > Then I would be more confident, that everything cooled down and
> > that I can start boost again.
> >
> > >
> > > > + tz->overheated = false;
> > > > + if (tz->boost_polling) {
> > > > + tz->boost_polling = false;
> > > > + tz->polling_delay = 0;
> > > > + monitor_thermal_zone(tz);
> > > > + }
> > >
> > > Overall, I believe this will work well only if the thermal zone is
> > > CPU.
> >
> > My assumption:
> >
> > When I enable boost at CPU, then I also shall cool down the CPU. And
> > the CPU zone seemed a natural choice.
> >
> > However I might be missing something, so hints are welcome.
> >
> > >
> > > Another suggestion is: We tried hard to remove all throttling
> > > logic from thermal_core.c.
> >
> > By throttling logic you mean:
> > if ((tz->temperature + (trip_temp >> 2)) and other conditions (like
> > trend measurement)?
>
> Yes. That is correct.
Ok.
>
> >
> > > May be we should include this kind of logic in
> > > step_wise.c ?
> >
> > It sounds interesting (since ->throttle at thermal_core.c is called
> > always when needed), but I'm afraid of a code duplication when one
> > use Boost with fair_share or other thermal governor.
>
> right. So, for the time being, (as part of this patch series)
> I am Okay to have this code in thermal_core.c. From the thermal
> subsystem perspective, we will (need to) work out a better/
> cleaner/easier approach for this later.
Thanks for understanding. I'm going to embed the trend checking in the
next version of this patch (to be more confident that I can reenable
boost).
>
> Thanks,
> Durga
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Thu, 04 Jul 2013 10:50:23 +0200, Lukasz Majewski wrote:
Dear Viresh, Rafael
Do you have any comments/feedback for me regarding those patches?
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB
> component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to
> include common code.
>
> Important design decisions:
>
> - Boost related code is compiled-in unconditionally to cpufreq core
> and disabled by default. The cpufreq_driver is responsibile for
> setting boost_supported flag and providing enable_boost callback(if
> HW support is needed). For software managed boost, special Kconfig
> flag - CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be
> selectable only when a target platform has thermal framework properly
> configured.
>
> - struct cpufreq_driver has been extended with boost related fields:
> -- boost_supported - when driver supports boosting
> -- enable_boost - callback to function, which is necessary to
> enable boost
>
> - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is
> visible _only_ when cpufreq driver supports Boost.
>
> - No special spin_lock for Boost was created. The one from cpufreq
> core was reused.
>
> - All available policies are now stored in a list.
>
> - The Boost code doesn't rely on any policy. When boost state is
> changed, then the policy list is iterated and proper adjustements are
> done.
>
> - To improve safety level, the thermal framework is also extended to
> disable software boosting, when thermal trip point is reached. Then
> it starts monitoring of target temperature to evaluate if boost can
> be enabled again. This emulates behaviour similar to HW managed boost
> (like x86)
>
> New patches for v5:
> cpufreq:boost:Kconfig: Enable software managed BOOST support at
> Kconfig Documentation:cpufreq:boost: Update BOOST documentation
>
> Patches dropped at v5:
> cpufreq: Calculate number of busy CPUs
> cpufreq: Enable software boost only when up to one busy core is
> running
>
> Tested at: HW:
> Exynos 4412 3.10 linux
> Exynos 4210 3.10 linux
> Compile tested x86_64 defconfig (acpi) - help with HW (Intel Nehalem)
> test needed
>
> The code has been rebased on top of kernel_pm/bleeding-edge (3.11-rc1)
>
>
> Lukasz Majewski (7):
> cpufreq: Store cpufreq policies in a list
> cpufreq: Add boost frequency support in core
> cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
> boost solution
> cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> framework
> thermal:boost: Automatic enable/disable of BOOST feature
> cpufreq:boost:Kconfig: Enable software managed BOOST support at
> Kconfig
> Documentation:cpufreq:boost: Update BOOST documentation
>
> Documentation/cpu-freq/boost.txt | 26 ++++-----
> drivers/cpufreq/Kconfig | 14 +++++
> drivers/cpufreq/acpi-cpufreq.c | 69 +++++++----------------
> drivers/cpufreq/cpufreq.c | 115
> ++++++++++++++++++++++++++++++++++++++
> drivers/cpufreq/exynos-cpufreq.c | 9 ++-
> drivers/cpufreq/freq_table.c | 47 +++++++++++++---
> drivers/thermal/thermal_core.c | 31 ++++++++++
> include/linux/cpufreq.h | 13 +++++
> include/linux/thermal.h | 2 + 9 files changed, 257
> insertions(+), 69 deletions(-)
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 9 July 2013 12:32, Lukasz Majewski <[email protected]> wrote:
> On Thu, 04 Jul 2013 10:50:23 +0200, Lukasz Majewski wrote:
>
> Dear Viresh, Rafael
>
> Do you have any comments/feedback for me regarding those patches?
I am busy in Linaro connect this week, but will see if I can get
some time to go over these.
Dear Zhang, Eduardo
Do you have any comments/feedback for me regarding this thermal
framework related patch?
I've already received some feedback from Durga for this patch, but I
think that maintainers are most welcome to express their opinion :-)
Thanks in advance.
> This patch provides auto disable/enable operation for boost. When any
> defined trip point is passed, the boost is disabled.
> In that moment thermal monitor workqueue is woken up and it monitors
> if the device temperature drops below 75% of the smallest trip point.
> When device cools down, the boost is enabled again.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v5:
> - Move boost disable code from cpu_cooling.c to thermal_core.c
> (to handle_non_critical_trips)
> - Extent struct thermal_zone_device by adding overheated bool flag
> - Implement auto enable of boost after device cools down
> - Introduce boost_polling flag, which indicates if thermal uses it's
> predefined pool delay or has woken up thermal workqueue only to wait
> until device cools down.
>
> Changes for v4:
> - New patch
>
> drivers/thermal/thermal_core.c | 31 +++++++++++++++++++++++++++++++
> include/linux/thermal.h | 2 ++
> 2 files changed, 33 insertions(+)
>
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c index d755440..12adbad 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -33,6 +33,7 @@
> #include <linux/idr.h>
> #include <linux/thermal.h>
> #include <linux/reboot.h>
> +#include <linux/cpufreq.h>
> #include <net/netlink.h>
> #include <net/genetlink.h>
>
> @@ -326,6 +327,15 @@ static void monitor_thermal_zone(struct
> thermal_zone_device *tz) static void handle_non_critical_trips(struct
> thermal_zone_device *tz, int trip, enum thermal_trip_type trip_type)
> {
> + if (cpufreq_boost_supported()) {
> + tz->overheated = true;
> + cpufreq_boost_trigger_state(0);
> + if (!tz->polling_delay) {
> + tz->boost_polling = true;
> + tz->polling_delay = 1000;
> + }
> + }
> +
> if (tz->governor)
> tz->governor->throttle(tz, trip);
> }
> @@ -453,6 +463,27 @@ static void thermal_zone_device_check(struct
> work_struct *work) struct thermal_zone_device *tz =
> container_of(work, struct thermal_zone_device,
> poll_queue.work);
> + long trip_temp;
> +
> + if (cpufreq_boost_supported() && tz->overheated) {
> + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> + /*
> + * Enable boost again only when current temperature
> is less
> + * than 75% of trip_temp[0]
> + */
> + if ((tz->temperature + (trip_temp >> 2)) <
> trip_temp) {
> + tz->overheated = false;
> + if (tz->boost_polling) {
> + tz->boost_polling = false;
> + tz->polling_delay = 0;
> + monitor_thermal_zone(tz);
> + }
> +
> + cpufreq_boost_trigger_state(1);
> + return;
> + }
> + }
> +
> thermal_zone_device_update(tz);
> }
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index a386a1c..f1aa3c2 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -172,6 +172,8 @@ struct thermal_zone_device {
> int emul_temperature;
> int passive;
> unsigned int forced_passive;
> + bool overheated;
> + bool boost_polling;
> const struct thermal_zone_device_ops *ops;
> const struct thermal_zone_params *tzp;
> struct thermal_governor *governor;
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Dear Viresh, Rafael,
> On Thu, 04 Jul 2013 10:50:23 +0200, Lukasz Majewski wrote:
>
> Dear Viresh, Rafael
>
> Do you have any comments/feedback for me regarding those patches?
>
Will you find time to review version 5 of cpufreq boost patch series?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Dear Zhang, Eduardo,
> Dear Zhang, Eduardo
>
> Do you have any comments/feedback for me regarding this thermal
> framework related patch?
>
> I've already received some feedback from Durga for this patch, but I
> think that maintainers are most welcome to express their opinion :-)
>
Will you find time to give me the feedback about proposed changes to
thermal_core.c regarding the cpufreq boost support?
> Thanks in advance.
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 16 July 2013 12:56, Lukasz Majewski <[email protected]> wrote:
> Dear Viresh, Rafael,
>
>> On Thu, 04 Jul 2013 10:50:23 +0200, Lukasz Majewski wrote:
>>
>> Dear Viresh, Rafael
>>
>> Do you have any comments/feedback for me regarding those patches?
>>
>
> Will you find time to review version 5 of cpufreq boost patch series?
This is a request or an order ?? :)
Yes, I have still kept these mails in my todo list.. Don't worry they wouldn't
be missed.
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> @@ -2056,6 +2058,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> subsys_interface_unregister(&cpufreq_interface);
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> + list_del(&cpufreq_policy_list);
You can't delete the list this way... You must have passed the list
entry you wanted to delete. More precisely link from the struct
cpufreq_policy.
Over that, it shouldn't be done at the time of unregistering cpufreq
driver but as and when cpus are removed and _cpu_remove_dev
is called.
On Tue, 16 Jul 2013 10:51:27 +0200 Viresh Kumar wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>
> > @@ -2056,6 +2058,7 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver)
> > subsys_interface_unregister(&cpufreq_interface);
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > + list_del(&cpufreq_policy_list);
>
> You can't delete the list this way... You must have passed the list
> entry you wanted to delete. More precisely link from the struct
> cpufreq_policy.
Yes. I shouldn't delete statically defined head of the list. Thanks for
spotting.
>
> Over that, it shouldn't be done at the time of unregistering cpufreq
> driver but as and when cpus are removed and _cpu_remove_dev
> is called.
OK, I will iterate the list at __cpufreq_remove_dev() and remove each
of them there.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> +int cpufreq_boost_trigger_state(int state)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + if (boost_enabled != state) {
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + boost_enabled = state;
> +
> + ret = cpufreq_driver->enable_boost(state);
> + if (ret)
> + boost_enabled = 0;
> +
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +
> + if (ret)
> + pr_err("%s: BOOST cannot enable (%d)\n",
Who said we are enabling it?
> + __func__, ret);
> + }
> +
> + return ret;
> +}
> +
> +int cpufreq_boost_supported(void)
> +{
> + if (cpufreq_driver)
> + return cpufreq_driver->boost_supported;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
> +
> +int cpufreq_boost_enabled(void)
> +{
> + return boost_enabled;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
> +
> +void cpufreq_set_boost_enabled(int state)
Maybe cpufreq_block_boost? As suggested by Rafael.
> +{
> + boost_enabled = state;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_set_boost_enabled);
> +
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -2001,6 +2094,22 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + if (cpufreq_driver->boost_supported) {
> + /*
> + * Check if boost driver provides function to enable boost -
> + * if not, use cpufreq_boost_enable_sw as default
> + */
> + if (!cpufreq_driver->enable_boost)
> + cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
& is redundant.
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> The struct cpufreq_driver has been extended to embrace the information
> related to boost support.
>
> When "boost_mode" device tree attribute is defined for a platform, the
> boost_supported flag is set. Moreover boost related attributes were
> exported.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
Don't we need to mark any frequencies in the freq table with BOOST?
How?
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> +config CPU_FREQ_BOOST_SW
> + bool "CPU frequency overclocking (BOOST)"
Name it "CPU Frequency Overclocking - Software"
> + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
Remote Exynos from here. If you want to enable it for your platform by
default, then select it from EXYNOS.
> + default n
> + help
> + This driver supports software managed overclocking (BOOST).
> + It allows usage of special frequencies for a particular processor
> + if thermal conditions are appropriate.
> +
> + It reguires, for safe operation, thermal framework with properly defined
> + trip points.
> +
> + If in doubt, say N.
> +
> config CPU_FREQ_STAT
> tristate "CPU frequency translation statistics"
> select CPU_FREQ_TABLE
> diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
> index 4f42fcc..7586b28 100644
> --- a/drivers/cpufreq/exynos-cpufreq.c
> +++ b/drivers/cpufreq/exynos-cpufreq.c
> @@ -288,7 +288,9 @@ static struct cpufreq_driver exynos_driver = {
>
> static int __init exynos_cpufreq_init(void)
> {
> +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> struct device_node *node = pdev->dev.of_node;
> +#endif
> int ret = -EINVAL;
>
> exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
> @@ -319,9 +321,10 @@ static int __init exynos_cpufreq_init(void)
> }
>
> locking_frequency = exynos_getspeed(0);
> +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> if (of_property_read_bool(node, "boost_mode"))
> exynos_driver.boost_supported = 1;
> -
> +#endif
Add a blank line here.
> register_pm_notifier(&exynos_cpufreq_nb);
>
> if (cpufreq_register_driver(&exynos_driver)) {
> --
> 1.7.10.4
>
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> -Reading the file is always supported, even if the processor does not
> -support boosting. In this case the file will be read-only and always
> -reads as "0". Explicitly changing the permissions and writing to that
> -file anyway will return EINVAL.
> +The file is exported only when cpufreq driver supports boosting.
> +Explicitly changing the permissions and writing to that file anyway will
> +return EINVAL.
For acpi-cpufreq reading the file should be always supported. And this
must be mentioned in doc.
On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> static void __init acpi_cpufreq_boost_init(void)
> @@ -953,33 +937,22 @@ static void __init acpi_cpufreq_boost_init(void)
> if (!msrs)
> return;
>
> - boost_supported = true;
> - boost_enabled = boost_state(0);
> + cpufreq_set_boost_enabled(boost_state(0));
> + acpi_cpufreq_driver.boost_supported = true;
You are again doing the same mistake. Boost must be
always supported for acpi-cpufreq with read permissions, as it was
earlier.
On Tue, 16 Jul 2013 15:18:57 +0530 Viresh Kumar [email protected]
wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > The struct cpufreq_driver has been extended to embrace the
> > information related to boost support.
> >
> > When "boost_mode" device tree attribute is defined for a platform,
> > the boost_supported flag is set. Moreover boost related attributes
> > were exported.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
>
> Don't we need to mark any frequencies in the freq table with BOOST?
> How?
The (trivial) patch is already prepared to enable BOOST at cpufreq for
Exynos4412. I will post it for v6. Sorry for not posting it earlier.
The whole patch is as follow:
static struct clk *cpu_clk;
static struct clk *mout_core;
static struct clk *sclk_mpll;
static struct clk *mout_apll;
static unsigned int exynos4x12_volt_table[] = {
1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
1000000, 987500, 975000, 950000, 925000, 900000, 900000
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
{L4, 1100 * 1000},
{L5, 1000 * 1000},
{L6, 900 * 1000},
{L7, 800 * 1000},
{L8, 700 * 1000},
{L9, 600 * 1000},
{L10, 500 * 1000},
{L11, 400 * 1000},
{L12, 300 * 1000},
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tue, 16 Jul 2013 15:34:02 +0530 Viresh Kumar [email protected]
wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > static void __init acpi_cpufreq_boost_init(void)
> > @@ -953,33 +937,22 @@ static void __init
> > acpi_cpufreq_boost_init(void) if (!msrs)
> > return;
> >
> > - boost_supported = true;
> > - boost_enabled = boost_state(0);
> > + cpufreq_set_boost_enabled(boost_state(0));
> > + acpi_cpufreq_driver.boost_supported = true;
>
> You are again doing the same mistake. Boost must be
> always supported for acpi-cpufreq with read permissions, as it was
> earlier.
The boost attribute is exported to sysfs only when boost is supported
by the driver (as we had agreed earlier).
The problem here is that the original acpi-cpufreq.c file had two
static flags:
static bool boost_enabled, boost_supported;
Both of them are not needed at acpi-cpufreq, since:
1. boost_enabled is defined at cpufreq.c core file.
2. boost_supported is defined at struct cpufreq_driver
(acpi_cpufreq_driver).
I've reused the boost_supported from acpi_cpufreq_driver structure to
avoid code duplication.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tue, 16 Jul 2013 15:31:43 +0530 Viresh Kumar [email protected]
wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > -Reading the file is always supported, even if the processor does
> > not -support boosting. In this case the file will be read-only and
> > always -reads as "0". Explicitly changing the permissions and
> > writing to that -file anyway will return EINVAL.
> > +The file is exported only when cpufreq driver supports boosting.
> > +Explicitly changing the permissions and writing to that file
> > anyway will +return EINVAL.
>
> For acpi-cpufreq reading the file should be always supported. And this
> must be mentioned in doc.
As fair as I've understood our previous discussion (at [*]) we have
agreed about this. We only export boost attribute when it is supported
by cpufreq_driver. Rafael was very clear about exporting boost
attribute:
"Simple: Export it only when supported."
[*]: Re: [PATCH v4 2/7] cpufreq: Add boost frequency support in core
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tue, 16 Jul 2013 15:28:40 +0530 Viresh Kumar [email protected]
wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>
> > +config CPU_FREQ_BOOST_SW
> > + bool "CPU frequency overclocking (BOOST)"
>
> Name it "CPU Frequency Overclocking - Software"
Thanks, I had a puzzle to came up with a good short name :-).
>
> > + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL && EXYNOS_THERMAL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>
> Remote Exynos from here. If you want to enable it for your platform by
> default, then select it from EXYNOS.
The purpose of the condition [*] here is to prevent from enabling
boost when thermal for Exynos is not supported.
Only for properly configured Exynos (when thermal + cpufreq is set) the
option is possible to enable. And by default it is disabled.
This shall prevent from accidental boost usage.
Please also note, that this switch only affects software based
boost. The HW boost (Intel ACPI) support doesn't depend on this Kconfig
setting.
>
> > + default n
> > + help
> > + This driver supports software managed overclocking (BOOST).
> > + It allows usage of special frequencies for a particular
> > processor
> > + if thermal conditions are appropriate.
> > +
> > + It reguires, for safe operation, thermal framework with
> > properly defined
> > + trip points.
> > +
> > + If in doubt, say N.
> > +
> > config CPU_FREQ_STAT
> > tristate "CPU frequency translation statistics"
> > select CPU_FREQ_TABLE
> > diff --git a/drivers/cpufreq/exynos-cpufreq.c
> > b/drivers/cpufreq/exynos-cpufreq.c index 4f42fcc..7586b28 100644
> > --- a/drivers/cpufreq/exynos-cpufreq.c
> > +++ b/drivers/cpufreq/exynos-cpufreq.c
> > @@ -288,7 +288,9 @@ static struct cpufreq_driver exynos_driver = {
> >
> > static int __init exynos_cpufreq_init(void)
> > {
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> > struct device_node *node = pdev->dev.of_node;
> > +#endif
> > int ret = -EINVAL;
> >
> > exynos_info = kzalloc(sizeof(struct exynos_dvfs_info),
> > GFP_KERNEL); @@ -319,9 +321,10 @@ static int __init
> > exynos_cpufreq_init(void) }
> >
> > locking_frequency = exynos_getspeed(0);
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> > if (of_property_read_bool(node, "boost_mode"))
> > exynos_driver.boost_supported = 1;
> > -
> > +#endif
>
> Add a blank line here.
OK
>
> > register_pm_notifier(&exynos_cpufreq_nb);
> >
> > if (cpufreq_register_driver(&exynos_driver)) {
> > --
> > 1.7.10.4
> >
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tue, 16 Jul 2013 15:11:54 +0530 Viresh Kumar [email protected]
wrote,
> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (boost_enabled != state) {
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + boost_enabled = state;
> > +
> > + ret = cpufreq_driver->enable_boost(state);
> > + if (ret)
> > + boost_enabled = 0;
> > +
> > + write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags); +
> > + if (ret)
> > + pr_err("%s: BOOST cannot enable (%d)\n",
>
> Who said we are enabling it?
You are right here - also disablement could fail. I will fix it.
>
> > + __func__, ret);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +int cpufreq_boost_supported(void)
> > +{
> > + if (cpufreq_driver)
> > + return cpufreq_driver->boost_supported;
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
> > +
> > +int cpufreq_boost_enabled(void)
> > +{
> > + return boost_enabled;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
> > +
> > +void cpufreq_set_boost_enabled(int state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>
> Maybe cpufreq_block_boost? As suggested by Rafael.
What do you mean by cpufreq_block_boost()? This name would reverse the
logic.
Function [*] is used to change boost_enabled static flag (defined at
cpufreq.c file) state according to acpi-cpufreq.c boost support status.
>
> > +{
> > + boost_enabled = state;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_set_boost_enabled);
> > +
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -2001,6 +2094,22 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + if (cpufreq_driver->boost_supported) {
> > + /*
> > + * Check if boost driver provides function to
> > enable boost -
> > + * if not, use cpufreq_boost_enable_sw as default
> > + */
> > + if (!cpufreq_driver->enable_boost)
> > + cpufreq_driver->enable_boost =
> > &cpufreq_boost_enable_sw;
>
> & is redundant.
Yes, correct. I will change that.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 16 July 2013 17:03, Lukasz Majewski <[email protected]> wrote:
> As fair as I've understood our previous discussion (at [*]) we have
> agreed about this. We only export boost attribute when it is supported
> by cpufreq_driver. Rafael was very clear about exporting boost
> attribute:
>
> "Simple: Export it only when supported."
>
> [*]: Re: [PATCH v4 2/7] cpufreq: Add boost frequency support in core
I don't want to search in the Archives but I am sure what we decided
earlier.
Rafael Said:
"Simple: Export it only when supported."
AND
"Don't change behavior of acpi-cpufreq driver"
If you see acpi-cpufreq driver carefully, it always creates "boost"
sysfs entry. If its not supported then it creates a read only entry.
So, please preserve that.
On 16 July 2013 17:20, Lukasz Majewski <[email protected]> wrote:
> On Tue, 16 Jul 2013 15:28:40 +0530 Viresh Kumar [email protected]
> wrote,
>> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
>> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>>
>> > +config CPU_FREQ_BOOST_SW
>> > + bool "CPU frequency overclocking (BOOST)"
>>
>> Name it "CPU Frequency Overclocking - Software"
>
> Thanks, I had a puzzle to came up with a good short name :-).
>
>>
>> > + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>>
>> Remote Exynos from here. If you want to enable it for your platform by
>> default, then select it from EXYNOS.
I misread it a bit. I wanted to say make it dependent only on THERMAL and
not on Exynos.
> The purpose of the condition [*] here is to prevent from enabling
> boost when thermal for Exynos is not supported.
Why? Can't others use it? Its not exynos specific :)
On 16 July 2013 17:36, Lukasz Majewski <[email protected]> wrote:
> On Tue, 16 Jul 2013 15:11:54 +0530 Viresh Kumar [email protected]
> wrote,
>> On 4 July 2013 14:20, Lukasz Majewski <[email protected]> wrote:
>> > +void cpufreq_set_boost_enabled(int state)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>
>>
>> Maybe cpufreq_block_boost? As suggested by Rafael.
>
> What do you mean by cpufreq_block_boost()? This name would reverse the
> logic.
>
> Function [*] is used to change boost_enabled static flag (defined at
> cpufreq.c file) state according to acpi-cpufreq.c boost support status.
I misread it again :(
So, what about adding another field in struct cpufreq_driver: boost_enabled?
And get rid of the global boost_enabled we have used? Similar to how
boost_supported is used, then we don't need this routine.
On Wed, 17 Jul 2013 10:58:40 +0530 Viresh Kumar [email protected]
wrote,
> On 16 July 2013 17:36, Lukasz Majewski <[email protected]> wrote:
> > On Tue, 16 Jul 2013 15:11:54 +0530 Viresh Kumar
> > [email protected] wrote,
> >> On 4 July 2013 14:20, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > +void cpufreq_set_boost_enabled(int state)
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
> >
> >>
> >> Maybe cpufreq_block_boost? As suggested by Rafael.
> >
> > What do you mean by cpufreq_block_boost()? This name would reverse
> > the logic.
> >
> > Function [*] is used to change boost_enabled static flag (defined at
> > cpufreq.c file) state according to acpi-cpufreq.c boost support
> > status.
>
> I misread it again :(
>
> So, what about adding another field in struct cpufreq_driver:
> boost_enabled? And get rid of the global boost_enabled we have used?
> Similar to how boost_supported is used, then we don't need this
> routine.
Ok, I will implement this.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 17 Jul 2013 10:54:55 +0530 Viresh Kumar [email protected]
wrote,
> On 16 July 2013 17:20, Lukasz Majewski <[email protected]> wrote:
> > On Tue, 16 Jul 2013 15:28:40 +0530 Viresh Kumar
> > [email protected] wrote,
> >> On 4 July 2013 14:20, Lukasz Majewski <[email protected]>
> >> wrote:
> >> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> >>
> >> > +config CPU_FREQ_BOOST_SW
> >> > + bool "CPU frequency overclocking (BOOST)"
> >>
> >> Name it "CPU Frequency Overclocking - Software"
> >
> > Thanks, I had a puzzle to came up with a good short name :-).
> >
> >>
> >> > + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
> >>
> >> Remote Exynos from here. If you want to enable it for your
> >> platform by default, then select it from EXYNOS.
I can change ARM_EXYNOS_CPUFREQ -> CPUFREQ at [*]
>
> I misread it a bit. I wanted to say make it dependent only on THERMAL
> and not on Exynos.
The cpufreq boost feature is possible to be enabled only when those [*]
dependencies are met. Moreover, it is disabled by default.
This means that not only THERMAL generic code must be supported, but
also EXYNOS specific one - like per SoC trip points [**].
With thermal it is possible (and correct) to only define THERMAL, with
no platform (in this case Exynos) specific definitions. To force
potential user to define [**], I think, that EXYNOS_THERMAL is required.
>
> > The purpose of the condition [*] here is to prevent from enabling
> > boost when thermal for Exynos is not supported.
>
> Why? Can't others use it? Its not exynos specific :)
No it is not exynos specific.
For other platform one need to define:
depends on CPUFREQ && (EXYNOS_THERMAL || <PLATFORM_SUPPORTED>_THERMAL)
Such condition improves my confidence about proper boost usage.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 17 Jul 2013 10:52:18 +0530 Viresh Kumar [email protected]
wrote,
> On 16 July 2013 17:03, Lukasz Majewski <[email protected]> wrote:
> > As fair as I've understood our previous discussion (at [*]) we have
> > agreed about this. We only export boost attribute when it is
> > supported by cpufreq_driver. Rafael was very clear about exporting
> > boost attribute:
> >
> > "Simple: Export it only when supported."
> >
> > [*]: Re: [PATCH v4 2/7] cpufreq: Add boost frequency support in core
>
> I don't want to search in the Archives but I am sure what we decided
> earlier.
At v4 there was the old acpi-cpufreq.c behaviour preserved (with always
exporting boost - when not supported ro, when supported rw).
Due to Rafael and Dirk comments it has been rewritten at v5:
http://thread.gmane.org/gmane.linux.kernel/1511831/match=patch+v4+2+7+cpufreq+add+boost+frequency+support+core
>
> Rafael Said:
> "Simple: Export it only when supported."
[*]
>
> AND
>
> "Don't change behavior of acpi-cpufreq driver"
[**]
>
> If you see acpi-cpufreq driver carefully, it always creates "boost"
> sysfs entry. If its not supported then it creates a read only entry.
For me those two statements [*] and [**] contradict:
At v5:
1. ARM - export "boost" only when supported (rw)
2. x86 - export boost only when x86 supports it (as rw). When x86
doesn't support HW boost - DO NOT export it at all.
At v4:
1. ARM - export "boost" only when supported (rw)
2. x86 - always export boost - no matter if supported or not. If not
supported, then export it as ro only.
>
> So, please preserve that.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 July 2013 12:47, Lukasz Majewski <[email protected]> wrote:
> On Wed, 17 Jul 2013 10:54:55 +0530 Viresh Kumar [email protected]
> wrote,
>> On 16 July 2013 17:20, Lukasz Majewski <[email protected]> wrote:
>> > On Tue, 16 Jul 2013 15:28:40 +0530 Viresh Kumar
>> > [email protected] wrote,
>> >> On 4 July 2013 14:20, Lukasz Majewski <[email protected]>
>> >> wrote:
>> >> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>> >>
>> >> > +config CPU_FREQ_BOOST_SW
>> >> > + bool "CPU frequency overclocking (BOOST)"
>> >>
>> >> Name it "CPU Frequency Overclocking - Software"
>> >
>> > Thanks, I had a puzzle to came up with a good short name :-).
>> >
>> >>
>> >> > + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
>> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>> >>
>> >> Remote Exynos from here. If you want to enable it for your
>> >> platform by default, then select it from EXYNOS.
>
> I can change ARM_EXYNOS_CPUFREQ -> CPUFREQ at [*]
We are in cpufreq Kconfig and so dependency is automatically
there on cpufreq.
>>
>> I misread it a bit. I wanted to say make it dependent only on THERMAL
>> and not on Exynos.
>
> The cpufreq boost feature is possible to be enabled only when those [*]
> dependencies are met. Moreover, it is disabled by default.
>
> This means that not only THERMAL generic code must be supported, but
> also EXYNOS specific one - like per SoC trip points [**].
>
> With thermal it is possible (and correct) to only define THERMAL, with
> no platform (in this case Exynos) specific definitions. To force
> potential user to define [**], I think, that EXYNOS_THERMAL is required.
>
>>
>> > The purpose of the condition [*] here is to prevent from enabling
>> > boost when thermal for Exynos is not supported.
>>
>> Why? Can't others use it? Its not exynos specific :)
>
> No it is not exynos specific.
> For other platform one need to define:
>
> depends on CPUFREQ && (EXYNOS_THERMAL || <PLATFORM_SUPPORTED>_THERMAL)
Exactly. I don't want this kind of mess to be present here.
People selecting this feature must know what it does and
dependency on a coolant is enough.
For other drivers, selecting this doesn't matter as they don't
support boost.
On 20 June 2013 03:55, Rafael J. Wysocki <[email protected]> wrote:
> On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
>> On Wed, 19 Jun 2013 10:48:53 -0700
>> Dirk Brandewie <[email protected]> wrote:
>>
>> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
>> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
>> > > + if (!cpufreq_driver->boost_supported)
>> > > + boost.attr.mode = 0444;
>> > > +
>> > > + ret = cpufreq_sysfs_create_file(&(boost.attr));
>> > > + if (ret) {
>> > > + pr_err("%s: cannot register global boost sysfs
>> > > file\n",
>> > > + __func__);
>> > > + goto err_null_driver;
>> > > + }
>> > > +
>> >
>> > I do not think the boost sysfs should be created at all if boost is
>> > not supported.
>>
>> This was my first thought. But unfortunately this "boost" attribute is
>> always exported at acpi-cpufreq.c and in my opinion is part of a
>> legacy API.
>>
>> I totally agree with the idea of exporting boost only when supported,
>> but I would like to know the community opinion about this (especially
>> Viresh and Rafael shall speak up).
>
> Simple: Export it only when supported.
Guys,
I got confused here. We originally decided to keep this feature as is
for acpi-cpufreq.
So, For acpi-cpufreq:
- when boost isn't supported: create sysfs boost with ro permissions
- when boost is supported: create sysfs boost with rw permissions
So, For others:
- create sysfs boost with rw permissions only when boost is supported
.
Do you want something else? or do you want to change behavior of
acpi-cpufreq driver? I don't why it was designed this way and what
applications use it.
On 17 July 2013 13:06, Lukasz Majewski <[email protected]> wrote:
> At v4 there was the old acpi-cpufreq.c behaviour preserved (with always
> exporting boost - when not supported ro, when supported rw).
>
> Due to Rafael and Dirk comments it has been rewritten at v5:
>
> http://thread.gmane.org/gmane.linux.kernel/1511831/match=patch+v4+2+7+cpufreq+add+boost+frequency+support+core
>
>
>>
>> Rafael Said:
>> "Simple: Export it only when supported."
> [*]
>
>>
>> AND
>>
>> "Don't change behavior of acpi-cpufreq driver"
> [**]
>>
>> If you see acpi-cpufreq driver carefully, it always creates "boost"
>> sysfs entry. If its not supported then it creates a read only entry.
>
> For me those two statements [*] and [**] contradict:
>
> At v5:
> 1. ARM - export "boost" only when supported (rw)
> 2. x86 - export boost only when x86 supports it (as rw). When x86
> doesn't support HW boost - DO NOT export it at all.
>
> At v4:
> 1. ARM - export "boost" only when supported (rw)
> 2. x86 - always export boost - no matter if supported or not. If not
> supported, then export it as ro only.
Okay, there is some confusion..
I have raised a query on your v4 mail.. lets see what people have to say.
On Wed, 17 Jul 2013 13:22:20 +0530 Viresh Kumar [email protected]
wrote,
> On 17 July 2013 12:47, Lukasz Majewski <[email protected]> wrote:
> > On Wed, 17 Jul 2013 10:54:55 +0530 Viresh Kumar
> > [email protected] wrote,
> >> On 16 July 2013 17:20, Lukasz Majewski <[email protected]>
> >> wrote:
> >> > On Tue, 16 Jul 2013 15:28:40 +0530 Viresh Kumar
> >> > [email protected] wrote,
> >> >> On 4 July 2013 14:20, Lukasz Majewski <[email protected]>
> >> >> wrote:
> >> >> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> >> >>
> >> >> > +config CPU_FREQ_BOOST_SW
> >> >> > + bool "CPU frequency overclocking (BOOST)"
> >> >>
> >> >> Name it "CPU Frequency Overclocking - Software"
> >> >
> >> > Thanks, I had a puzzle to came up with a good short name :-).
> >> >
> >> >>
> >> >> > + depends on ARM_EXYNOS_CPUFREQ && EXYNOS_THERMAL
> >> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
> >> >>
> >> >> Remote Exynos from here. If you want to enable it for your
> >> >> platform by default, then select it from EXYNOS.
> >
> > I can change ARM_EXYNOS_CPUFREQ -> CPUFREQ at [*]
>
> We are in cpufreq Kconfig and so dependency is automatically
> there on cpufreq.
So then, it can be removed.
>
> >>
> >> I misread it a bit. I wanted to say make it dependent only on
> >> THERMAL and not on Exynos.
> >
> > The cpufreq boost feature is possible to be enabled only when those
> > [*] dependencies are met. Moreover, it is disabled by default.
> >
> > This means that not only THERMAL generic code must be supported, but
> > also EXYNOS specific one - like per SoC trip points [**].
> >
> > With thermal it is possible (and correct) to only define THERMAL,
> > with no platform (in this case Exynos) specific definitions. To
> > force potential user to define [**], I think, that EXYNOS_THERMAL
> > is required.
> >
> >>
> >> > The purpose of the condition [*] here is to prevent from enabling
> >> > boost when thermal for Exynos is not supported.
> >>
> >> Why? Can't others use it? Its not exynos specific :)
> >
> > No it is not exynos specific.
> > For other platform one need to define:
> >
> > depends on CPUFREQ && (EXYNOS_THERMAL ||
> > <PLATFORM_SUPPORTED>_THERMAL)
>
> Exactly. I don't want this kind of mess to be present here.
>
> People selecting this feature must know what it does and
> dependency on a coolant is enough.
>
> For other drivers, selecting this doesn't matter as they don't
> support boost.
Then it should be enough to only write:
depends on THERMAL
(since CPUFREQ is already enabled for entering this menu).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wed, 17 Jul 2013 13:29:26 +0530 Viresh Kumar [email protected]
wrote,
> On 17 July 2013 13:06, Lukasz Majewski <[email protected]> wrote:
> > At v4 there was the old acpi-cpufreq.c behaviour preserved (with
> > always exporting boost - when not supported ro, when supported rw).
> >
> > Due to Rafael and Dirk comments it has been rewritten at v5:
> >
> > http://thread.gmane.org/gmane.linux.kernel/1511831/match=patch+v4+2+7+cpufreq+add+boost+frequency+support+core
> >
> >
> >>
> >> Rafael Said:
> >> "Simple: Export it only when supported."
> > [*]
> >
> >>
> >> AND
> >>
> >> "Don't change behavior of acpi-cpufreq driver"
> > [**]
> >>
> >> If you see acpi-cpufreq driver carefully, it always creates "boost"
> >> sysfs entry. If its not supported then it creates a read only
> >> entry.
> >
> > For me those two statements [*] and [**] contradict:
> >
> > At v5:
> > 1. ARM - export "boost" only when supported (rw)
> > 2. x86 - export boost only when x86 supports it (as rw). When x86
> > doesn't support HW boost - DO NOT export it at all.
> >
> > At v4:
> > 1. ARM - export "boost" only when supported (rw)
> > 2. x86 - always export boost - no matter if supported or not. If not
> > supported, then export it as ro only.
>
> Okay, there is some confusion..
>
> I have raised a query on your v4 mail.. lets see what people have to
> say.
Ok.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 July 2013 13:42, Lukasz Majewski <[email protected]> wrote:
> Then it should be enough to only write:
>
> depends on THERMAL
>
> (since CPUFREQ is already enabled for entering this menu).
Correct
On Wed, 17 Jul 2013 10:29:15 +0200 Viresh Kumar [email protected]
wrote,
> On 17 July 2013 13:42, Lukasz Majewski <[email protected]> wrote:
> > Then it should be enough to only write:
> >
> > depends on THERMAL
> >
> > (since CPUFREQ is already enabled for entering this menu).
>
> Correct
OK.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Wednesday, July 17, 2013 01:28:29 PM Viresh Kumar wrote:
> On 20 June 2013 03:55, Rafael J. Wysocki <[email protected]> wrote:
> > On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
> >> On Wed, 19 Jun 2013 10:48:53 -0700
> >> Dirk Brandewie <[email protected]> wrote:
> >>
> >> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
>
> >> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> >> > > + if (!cpufreq_driver->boost_supported)
> >> > > + boost.attr.mode = 0444;
> >> > > +
> >> > > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> >> > > + if (ret) {
> >> > > + pr_err("%s: cannot register global boost sysfs
> >> > > file\n",
> >> > > + __func__);
> >> > > + goto err_null_driver;
> >> > > + }
> >> > > +
> >> >
> >> > I do not think the boost sysfs should be created at all if boost is
> >> > not supported.
> >>
> >> This was my first thought. But unfortunately this "boost" attribute is
> >> always exported at acpi-cpufreq.c and in my opinion is part of a
> >> legacy API.
> >>
> >> I totally agree with the idea of exporting boost only when supported,
> >> but I would like to know the community opinion about this (especially
> >> Viresh and Rafael shall speak up).
> >
> > Simple: Export it only when supported.
>
> Guys,
>
> I got confused here. We originally decided to keep this feature as is
> for acpi-cpufreq.
>
> So, For acpi-cpufreq:
> - when boost isn't supported: create sysfs boost with ro permissions
> - when boost is supported: create sysfs boost with rw permissions
>
> So, For others:
> - create sysfs boost with rw permissions only when boost is supported
>
> .
>
> Do you want something else? or do you want to change behavior of
> acpi-cpufreq driver? I don't why it was designed this way and what
> applications use it.
First off, I'm not sure how many applications actually use it and I think,
if any, they should be able cope with the attribute not being present.
Of course, if it turns out that yes, there are applications using it and no,
they cannot cope with the missing attribute, we'll need to address this.
That said such applications wouldn't work with earlier kernels in which that
attribute wasn't present at all, so I suppose this is really unlikely.
So, do whichever makes more sense to you: Design things to preserve the old
behavior (which is sightly confusing) or design them to expose the attribute
if the feature is actually supported and be prepared to address the (unlikely)
case when some hypothetical applications break because of that.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On 17 July 2013 17:01, Rafael J. Wysocki <[email protected]> wrote:
> First off, I'm not sure how many applications actually use it and I think,
> if any, they should be able cope with the attribute not being present.
>
> Of course, if it turns out that yes, there are applications using it and no,
> they cannot cope with the missing attribute, we'll need to address this.
> That said such applications wouldn't work with earlier kernels in which that
> attribute wasn't present at all, so I suppose this is really unlikely.
>
> So, do whichever makes more sense to you: Design things to preserve the old
> behavior (which is sightly confusing) or design them to expose the attribute
> if the feature is actually supported and be prepared to address the (unlikely)
> case when some hypothetical applications break because of that.
Okay. Its better to keep it the way Lukasz designed it in his last patchset.
On Wed, 17 Jul 2013 18:31:19 +0530 Viresh Kumar [email protected]
wrote,
> On 17 July 2013 17:01, Rafael J. Wysocki <[email protected]> wrote:
> > First off, I'm not sure how many applications actually use it and I
> > think, if any, they should be able cope with the attribute not
> > being present.
> >
> > Of course, if it turns out that yes, there are applications using
> > it and no, they cannot cope with the missing attribute, we'll need
> > to address this. That said such applications wouldn't work with
> > earlier kernels in which that attribute wasn't present at all, so I
> > suppose this is really unlikely.
> >
> > So, do whichever makes more sense to you: Design things to preserve
> > the old behavior (which is sightly confusing) or design them to
> > expose the attribute if the feature is actually supported and be
> > prepared to address the (unlikely) case when some hypothetical
> > applications break because of that.
>
> Okay. Its better to keep it the way Lukasz designed it in his last
> patchset.
To be 100% sure - we export boost only when supported (as proposed at v5).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 17 July 2013 20:29, Lukasz Majewski <[email protected]> wrote:
> To be 100% sure - we export boost only when supported (as proposed at v5).
Yes.
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing set_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- boost_enabled - boost state
-- set_boost - callback to function, which is necessary to
enable/disable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- All available policies are now stored in a list.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
New patches for v6:
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Tested at HW:
Exynos 4412 3.11-rc1 Linux
Intel Core i7-3770 3.11-rc1 Linux
Lukasz Majewski (8):
cpufreq: Store cpufreq policies in a list
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Provide support for software managed BOOST
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
Documentation:cpufreq:boost: Update BOOST documentation
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Documentation/cpu-freq/boost.txt | 26 +++----
drivers/cpufreq/Kconfig | 3 +
drivers/cpufreq/Kconfig.arm | 16 +++++
drivers/cpufreq/acpi-cpufreq.c | 87 ++++++++----------------
drivers/cpufreq/cpufreq.c | 124 +++++++++++++++++++++++++++++++++-
drivers/cpufreq/exynos-cpufreq.c | 6 ++
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 53 +++++++++++++--
drivers/thermal/thermal_core.c | 55 +++++++++++++++
include/linux/cpufreq.h | 26 +++++++
include/linux/thermal.h | 2 +
11 files changed, 321 insertions(+), 79 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency
above its normal operation limits. Such mode shall be only used for a
short time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) overclocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code. By default boost is disabled. One global
attribute is available at: /sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with a proper call
to sysfs.
The cpufreq_boost_trigger_state() function is defined non static on purpose.
It is used later with thermal subsystem to provide automatic enable/disable
of the BOOST feature.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- Remove sysfs boost attribute when subsys_iterface_unregister() fails
- Move global boost_enabled variable from cpufreq.c to platform dependent
struct cpufreq_driver
- pr_err() message is also printed when boost disable fails
- Call __cpufreq_governor() to force recalculation of next frequency when
boost is triggered. It is needed with i.e. performance class of governors
- Change cpufreq_boost_enable_sw() -> cpufreq_boost_set_sw()
- Rename .enable_boost function pointer to .set_boost
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 115 +++++++++++++++++++++++++++++++++++++++++-
drivers/cpufreq/freq_table.c | 53 ++++++++++++++++---
include/linux/cpufreq.h | 10 ++++
3 files changed, 170 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 172a25e..15f8d79 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -377,6 +377,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %s BOOST!\n", __func__,
+ enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -1970,6 +1997,70 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_set_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (!ret) {
+ policy->user_policy.max = policy->max;
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (cpufreq_driver->boost_enabled == state)
+ return 0;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ ret = cpufreq_driver->set_boost(state);
+ if (ret) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = 0;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_err("%s: BOOST cannot %s\n", __func__,
+ state ? "enabled" : "disabled");
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (cpufreq_driver)
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return cpufreq_driver->boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2008,9 +2099,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_boost_supported()) {
+ /*
+ * Check if boost driver provides function to enable boost -
+ * if not, use cpufreq_boost_set_sw as default
+ */
+ if (!cpufreq_driver->set_boost)
+ cpufreq_driver->set_boost = cpufreq_boost_set_sw;
+
+ ret = cpufreq_sysfs_create_file(&(boost.attr));
+ if (ret) {
+ pr_err("%s: cannot register global BOOST sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
- goto err_null_driver;
+ goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
@@ -2037,6 +2144,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_boost_unreg:
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&(boost.attr));
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2063,6 +2173,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&(boost.attr));
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f0d8741..17d03fc 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,6 +34,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -171,7 +175,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ bool show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -186,6 +191,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq
+ * display BOOST freqs
+ *
+ * show_boost = false and driver_data = BOOST freq
+ * show_boost = true and driver_data != BOOST freq
+ * continue - do not display anything
+ *
+ * show_boost = false and driver_data != BOOST freq
+ * display NON BOOST freqs
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -194,14 +213,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 0);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, 1);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d8e30fc..49a73c9 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -267,6 +267,11 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost) (int state);
};
/* flags */
@@ -410,6 +415,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+#define CPUFREQ_BOOST_FREQ ~2
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
@@ -429,11 +435,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- Disable boost only when supported and enabled
- Protect boost related thermal_zone_device struct fields with mutex
- Evaluate temperature trend during boost enable decision
- Create separate methods to handle boost enable/disable
(thermal_boost_{enable|disable}) operations
- Boost is disabled at any trip point passage (not only the non critical one)
- Add stub definitions for cpufreq boost functions used when
CONFIG_CPU_FREQ is NOT defined.
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
include/linux/cpufreq.h | 15 +++++++++++
include/linux/thermal.h | 2 ++
3 files changed, 72 insertions(+)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1f02e8e..8f4be55 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -354,9 +355,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
}
+static int thermal_boost_enable(struct thermal_zone_device *tz)
+{
+ enum thermal_trend trend = get_tz_trend(tz, 0);
+ long trip_temp;
+
+ if (!tz->ops->get_trip_temp || !tz->overheated)
+ return -EPERM;
+ if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
+ return -EBUSY;
+
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ mutex_lock(&tz->lock);
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ }
+ mutex_unlock(&tz->lock);
+ cpufreq_boost_trigger_state(1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void thermal_boost_disable(struct thermal_zone_device *tz)
+{
+ cpufreq_boost_trigger_state(0);
+
+ /*
+ * If no workqueue for monitoring is running - start one with
+ * 1000 ms monitoring period
+ * If workqueue already running - do not change its period and only
+ * test if target CPU has cooled down
+ */
+ mutex_lock(&tz->lock);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ tz->overheated = true;
+ mutex_unlock(&tz->lock);
+}
+
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ if (cpufreq_boost_supported() && cpufreq_boost_enabled())
+ thermal_boost_disable(tz);
tz->ops->get_trip_type(tz, trip, &type);
@@ -455,6 +506,10 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ if (cpufreq_boost_supported())
+ if (!thermal_boost_enable(tz))
+ return;
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 49a73c9..3d9276d 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -435,9 +435,24 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index);
+#ifdef CONFIG_CPU_FREQ
int cpufreq_boost_trigger_state(int state);
int cpufreq_boost_supported(void);
int cpufreq_boost_enabled(void);
+#else
+static inline int cpufreq_boost_trigger_state(int state)
+{
+ return 0;
+}
+static inline int cpufreq_boost_supported(void)
+{
+ return 0;
+}
+static inline int cpufreq_boost_enabled(void)
+{
+ return 0;
+}
+#endif
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1c..f1aa3c2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
The cpufreq_driver's boost_supported flag is true only when boost
support is explicitly enabled. Boost related attributes are exported only
under the same condition.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- Replace exynos_driver.boost_supported = 1 to = true
- Protect boost attributes export with CONFIG_CPU_FREQ_BOOST_SW
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 9ae1871..175172d9 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+#ifdef CONFIG_CPU_FREQ_BOOST_SW
+ &cpufreq_freq_attr_scaling_boost_freqs,
+#endif
NULL,
};
@@ -332,6 +335,9 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
locking_frequency = exynos_getspeed(0);
+#ifdef CONFIG_CPU_FREQ_BOOST_SW
+ exynos_driver.boost_supported = true;
+#endif
register_pm_notifier(&exynos_cpufreq_nb);
if (cpufreq_register_driver(&exynos_driver)) {
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- None
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
frequency, which can be only enabled for BOOST mode.
This frequency shall be used only for limited time, since it might cause
target device to overheat.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- New patch
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index e270b42..367f600 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = {
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
option the software managed boost is enabled. It also selects thermal
subsystem to be compiled in. Thermal is necessary for disabling boost
and cooling down the device when overheating detected.
Boost _MUST_NOT_ work without thermal subsystem with properly defined
overheating temperatures.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
- Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
added. It depends on ARM_EXYNOS_CPUFREQ options and selects
EXYNOS_THERMAL with the main boost config [1].
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 3 +++
drivers/cpufreq/Kconfig.arm | 16 ++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 534fcb8..3f058a3 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,9 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index de4d5d9..c8abb93 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -55,6 +55,22 @@ config ARM_EXYNOS5440_CPUFREQ
different than previous exynos controllers so not using
the common exynos framework.
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ default n
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly
+ defined trip points.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- Perform acpi_cpufreq_boost_init initialization before cpufreq_driver
registration
- Compile store_boost() only when CONFIG_X86_ACPI_CPUFREQ_CPB defined
- Use boost_enabled flag defined at acpi_cpufreq_driver to store information
about boost state
- Instead of using cpufreq_set_boost_enabled(), modify the boost_enable in
the acpi driver code
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 87 ++++++++++++++--------------------------
1 file changed, 30 insertions(+), 57 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 3926402..509764c 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -81,7 +81,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -134,49 +133,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
get_online_cpus();
-
boost_set_msrs(val, cpu_online_mask);
-
put_online_cpus();
-
- boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
-}
-
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
+ return 0;
}
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -187,15 +153,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
+static ssize_t store_boost(const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val = 0;
+
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost((int) val);
+
+ return count;
+}
+
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
}
static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
@@ -583,7 +566,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -943,43 +926,34 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
+ .set_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
{
+ acpi_cpufreq_driver.boost_supported = false;
if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) {
msrs = msrs_alloc();
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
-
+ acpi_cpufreq_driver.boost_supported = true;
+ acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
+ cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb;
}
#endif
+ acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret)
free_acpi_perf_data();
- else
- acpi_cpufreq_boost_init();
return ret;
}
--
1.7.10.4
Policies available in a cpufreq framework are now linked together. They are
accessible via cpufreq_policy_list defined at cpufreq core.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v6:
- Move policy list entry delete code to __cpufreq_remove_dev()
- Protect operations on cpufreq_policy_list elements with lock
Changes for v5:
- Call list_add() only when device successfully added
Changes for v4:
- New patch
drivers/cpufreq/cpufreq.c | 9 +++++++++
include/linux/cpufreq.h | 1 +
2 files changed, 10 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0937b8d..172a25e 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -46,6 +46,7 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock);
+static LIST_HEAD(cpufreq_policy_list);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -1054,6 +1055,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
if (ret)
goto err_out_unregister;
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_add(&policy->policy_list, &cpufreq_policy_list);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
pr_debug("initialization complete\n");
@@ -1202,6 +1207,10 @@ static int __cpufreq_remove_dev(struct device *dev,
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_del(&data->policy_list);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
free_cpumask_var(data->related_cpus);
free_cpumask_var(data->cpus);
kfree(data);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 90d5a15..d8e30fc 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -117,6 +117,7 @@ struct cpufreq_policy {
struct cpufreq_real_policy user_policy;
+ struct list_head policy_list;
struct kobject kobj;
struct completion kobj_unregister;
int transition_ongoing; /* Tracks transition status */
--
1.7.10.4
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> /*********************************************************************
> + * BOOST *
> + *********************************************************************/
> +static int cpufreq_boost_set_sw(int state)
> +{
> + struct cpufreq_frequency_table *freq_table;
> + struct cpufreq_policy *policy;
> + int ret = -EINVAL;
> +
> + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
> + freq_table = cpufreq_frequency_get_table(policy->cpu);
> + if (freq_table) {
> + ret = cpufreq_frequency_table_cpuinfo(policy,
> + freq_table);
> + if (!ret) {
> + policy->user_policy.max = policy->max;
> + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
> + }
> + }
> + }
> +
> + return ret;
> +}
> +
> +int cpufreq_boost_trigger_state(int state)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + if (cpufreq_driver->boost_enabled == state)
> + return 0;
> +
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + cpufreq_driver->boost_enabled = state;
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
Not sure if we should leave the lock at this point of time, as we
haven't enabled boost until now.
If somebody tries to use this variable at this point of time, then
it would get the wrong information about it.
> + ret = cpufreq_driver->set_boost(state);
> + if (ret) {
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + cpufreq_driver->boost_enabled = 0;
should be:
cpufreq_driver->boost_enabled = !state;
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +
> + pr_err("%s: BOOST cannot %s\n", __func__,
s/BOOST cannot %s/Cannot %s BOOST
> + state ? "enabled" : "disabled");
> + }
> +
> + return ret;
> +}
> +
> +int cpufreq_boost_supported(void)
> +{
> + if (cpufreq_driver)
This routine is always called from places where cpufreq_driver
can't be NULL..
--contd--
> + return cpufreq_driver->boost_supported;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
> +
> +int cpufreq_boost_enabled(void)
> +{
> + return cpufreq_driver->boost_enabled;
And if above check is necessary, then don't you need to check
it here as well?
> +}
> +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
> +
> +/*********************************************************************
> * REGISTER / UNREGISTER CPUFREQ DRIVER *
> *********************************************************************/
>
> @@ -2008,9 +2099,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> cpufreq_driver = driver_data;
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> + if (cpufreq_boost_supported()) {
> + /*
> + * Check if boost driver provides function to enable boost -
s/boost driver/driver
> + * if not, use cpufreq_boost_set_sw as default
> + */
> + if (!cpufreq_driver->set_boost)
> + cpufreq_driver->set_boost = cpufreq_boost_set_sw;
> +
> + ret = cpufreq_sysfs_create_file(&(boost.attr));
You don't need braces around boost.attr.
> + if (ret) {
> + pr_err("%s: cannot register global BOOST sysfs file\n",
> + __func__);
> + goto err_null_driver;
> + }
> + }
> +
> ret = subsys_interface_register(&cpufreq_interface);
> if (ret)
> - goto err_null_driver;
> + goto err_boost_unreg;
>
> if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
> int i;
> @@ -2037,6 +2144,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
> return 0;
> err_if_unreg:
> subsys_interface_unregister(&cpufreq_interface);
> +err_boost_unreg:
> + if (cpufreq_boost_supported())
> + cpufreq_sysfs_remove_file(&(boost.attr));
same here.
> err_null_driver:
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> cpufreq_driver = NULL;
> @@ -2063,6 +2173,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
> pr_debug("unregistering driver %s\n", driver->name);
>
> subsys_interface_unregister(&cpufreq_interface);
> + if (cpufreq_boost_supported())
> + cpufreq_sysfs_remove_file(&(boost.attr));
here too.
> +
> unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 0);
s/0/false
> +}
> +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
> + char *buf)
> +{
> + return show_available_freqs(policy, buf, 1);
s/1/true
> +}
Looks good mostly.. We Should be to get it in 3.12 :)
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
> static void __init acpi_cpufreq_boost_init(void)
> {
> + acpi_cpufreq_driver.boost_supported = false;
Would be better if we do this in else of below if.
> if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) {
> msrs = msrs_alloc();
> @@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
> *iter = &cpb;
> }
> #endif
> + acpi_cpufreq_boost_init();
We are calling it before registering cpufreq driver. Will this have
any complications?
> ret = cpufreq_register_driver(&acpi_cpufreq_driver);
> if (ret)
> free_acpi_perf_data();
> - else
> - acpi_cpufreq_boost_init();
>
> return ret;
On Fri, 26 Jul 2013 12:58:02 +0530 Viresh Kumar wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/acpi-cpufreq.c
> > b/drivers/cpufreq/acpi-cpufreq.c
>
> > static void __init acpi_cpufreq_boost_init(void)
> > {
> > + acpi_cpufreq_driver.boost_supported = false;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>
> Would be better if we do this in else of below if.
We need to set boost_supported = false at [*] for the case when:
1. msrs_alloc fails
or
2. acpi_cpufreq is built as a module and can be inserted and removed
several times. Without [*] we could end up with wrong (not false)
initial state.
>
> > if (boot_cpu_has(X86_FEATURE_CPB) ||
> > boot_cpu_has(X86_FEATURE_IDA)) { msrs = msrs_alloc();
>
>
> > @@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
> > *iter = &cpb;
> > }
> > #endif
> > + acpi_cpufreq_boost_init();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [**]
>
> We are calling it before registering cpufreq driver. Will this have
> any complications?
When we call [**] after the cpufreq_register_driver [***] we end up with
sysfs boost attribute not exported at x86.
The boost attribute is exported at [***] only when
acpi_cpufreq.boost_supported = true. However support for boost at x86
is evaluated at acpi_cpufreq_boost_init().
>
> > ret = cpufreq_register_driver(&acpi_cpufreq_driver);
> > if (ret)
> > free_acpi_perf_data();
> > - else
> > - acpi_cpufreq_boost_init();
> >
> > return ret;
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 12:47:15 +0530 Viresh Kumar wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>
> > /*********************************************************************
> > + *
> > BOOST *
> > +
> > *********************************************************************/
> > +static int cpufreq_boost_set_sw(int state) +{
> > + struct cpufreq_frequency_table *freq_table;
> > + struct cpufreq_policy *policy;
> > + int ret = -EINVAL;
> > +
> > + list_for_each_entry(policy, &cpufreq_policy_list,
> > policy_list) {
> > + freq_table =
> > cpufreq_frequency_get_table(policy->cpu);
> > + if (freq_table) {
> > + ret =
> > cpufreq_frequency_table_cpuinfo(policy,
> > + freq_table);
> > + if (!ret) {
> > + policy->user_policy.max =
> > policy->max;
> > + __cpufreq_governor(policy,
> > CPUFREQ_GOV_LIMITS);
> > + }
> > + }
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (cpufreq_driver->boost_enabled == state)
> > + return 0;
> > +
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + cpufreq_driver->boost_enabled = state;
> > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
^^^^^^^^^^^^^^^^^^^^ [*]
>
> Not sure if we should leave the lock at this point of time, as we
> haven't enabled boost until now.
The problem here is with the cpufreq_driver->set_boost() call.
I tried to avoid acquiring lock at one function and release it at
another (in this case cpufreq_boost_set_sw), especially since the
__cpufreq_governor() acquires its own lock - good place for deadlock.
Is it OK for you to grab lock at one function
(cpufreq_boost_trigger_state()) and then at other function
(cpufreq_boost_set_sw) release it before calling __cpufreq_governor()
and grab it again after its completion?
>
> If somebody tries to use this variable at this point of time, then
> it would get the wrong information about it.
>
> > + ret = cpufreq_driver->set_boost(state);
> > + if (ret) {
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + cpufreq_driver->boost_enabled = 0;
>
> should be:
> cpufreq_driver->boost_enabled = !state;
For me = 0 (or = false) is more readable.
If you wish, I will change it to = !state.
>
> > + write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags); +
> > + pr_err("%s: BOOST cannot %s\n", __func__,
>
> s/BOOST cannot %s/Cannot %s BOOST
Ok.
>
> > + state ? "enabled" : "disabled");
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +int cpufreq_boost_supported(void)
> > +{
> > + if (cpufreq_driver)
>
> This routine is always called from places where cpufreq_driver
> can't be NULL..
It is also called from thermal. And it happens that thermal is
initialized earlier.
Then "NULL pointer dereference" happens.
>
> --contd--
>
> > + return cpufreq_driver->boost_supported;
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
> > +
> > +int cpufreq_boost_enabled(void)
> > +{
> > + return cpufreq_driver->boost_enabled;
^^^^^^^^^^^^^^ [1]
>
> And if above check is necessary, then don't you need to check
> it here as well?
Because on thermal I check first if cpufreq_boost_supported() is true.
If boost is not supported then check for cpufreq_boost_enabled() is not
performed.
In my opinion at [1] we don't need the if (cpufreq_driver) check.
But it is up to you to decide.
>
> > +}
> > +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
> > +
> > +/*********************************************************************
> > * REGISTER / UNREGISTER CPUFREQ
> > DRIVER *
> > *********************************************************************/
> >
> > @@ -2008,9 +2099,25 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > + if (cpufreq_boost_supported()) {
> > + /*
> > + * Check if boost driver provides function to
> > enable boost -
>
> s/boost driver/driver
Ok.
>
> > + * if not, use cpufreq_boost_set_sw as default
> > + */
> > + if (!cpufreq_driver->set_boost)
> > + cpufreq_driver->set_boost =
> > cpufreq_boost_set_sw; +
> > + ret = cpufreq_sysfs_create_file(&(boost.attr));
>
> You don't need braces around boost.attr.
Ok.
>
> > + if (ret) {
> > + pr_err("%s: cannot register global BOOST
> > sysfs file\n",
> > + __func__);
> > + goto err_null_driver;
> > + }
> > + }
> > +
> > ret = subsys_interface_register(&cpufreq_interface);
> > if (ret)
> > - goto err_null_driver;
> > + goto err_boost_unreg;
> >
> > if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
> > int i;
> > @@ -2037,6 +2144,9 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) return 0;
> > err_if_unreg:
> > subsys_interface_unregister(&cpufreq_interface);
> > +err_boost_unreg:
> > + if (cpufreq_boost_supported())
> > + cpufreq_sysfs_remove_file(&(boost.attr));
>
> same here.
Ok.
>
> > err_null_driver:
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > cpufreq_driver = NULL;
> > @@ -2063,6 +2173,9 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> > subsys_interface_unregister(&cpufreq_interface);
> > + if (cpufreq_boost_supported())
> > + cpufreq_sysfs_remove_file(&(boost.attr));
>
> here too.
Ok.
>
> > +
> > unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
>
> > +static ssize_t scaling_available_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 0);
>
> s/0/false
Ok.
>
> > +}
>
> > +static ssize_t scaling_boost_frequencies_show(struct
> > cpufreq_policy *policy,
> > + char *buf)
> > +{
> > + return show_available_freqs(policy, buf, 1);
>
> s/1/true
Ok.
>
> > +}
>
> Looks good mostly.. We Should be to get it in 3.12 :)
If we agree about above comments, I will post v7 ASAP.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 26 July 2013 13:39, Lukasz Majewski <[email protected]> wrote:
> On Fri, 26 Jul 2013 12:58:02 +0530 Viresh Kumar wrote,
>> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>> > diff --git a/drivers/cpufreq/acpi-cpufreq.c
>> > b/drivers/cpufreq/acpi-cpufreq.c
>>
>> > static void __init acpi_cpufreq_boost_init(void)
>> > {
>> > + acpi_cpufreq_driver.boost_supported = false;
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>>
>> Would be better if we do this in else of below if.
>
> We need to set boost_supported = false at [*] for the case when:
> 1. msrs_alloc fails
> or
> 2. acpi_cpufreq is built as a module and can be inserted and removed
> several times. Without [*] we could end up with wrong (not false)
> initial state.
Hmm.. Now that I see the code again, we don't need to set it to false
as it is a global variable and this field is already set to false..
>> > if (boot_cpu_has(X86_FEATURE_CPB) ||
>> > boot_cpu_has(X86_FEATURE_IDA)) { msrs = msrs_alloc();
>>
>>
>> > @@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
>> > *iter = &cpb;
>> > }
>> > #endif
>> > + acpi_cpufreq_boost_init();
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [**]
>>
>> We are calling it before registering cpufreq driver. Will this have
>> any complications?
>
> When we call [**] after the cpufreq_register_driver [***] we end up with
> sysfs boost attribute not exported at x86.
> The boost attribute is exported at [***] only when
> acpi_cpufreq.boost_supported = true. However support for boost at x86
> is evaluated at acpi_cpufreq_boost_init().
I understand why you moved it above cpufreq driver register. I was thinking
if there can be few side effects of this..
On 26 July 2013 14:03, Lukasz Majewski <[email protected]> wrote:
> On Fri, 26 Jul 2013 12:47:15 +0530 Viresh Kumar wrote,
>> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>> > +int cpufreq_boost_trigger_state(int state)
>> > +{
>> > + unsigned long flags;
>> > + int ret = 0;
>> > +
>> > + if (cpufreq_driver->boost_enabled == state)
>> > + return 0;
>> > +
>> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
>> > + cpufreq_driver->boost_enabled = state;
>> > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> ^^^^^^^^^^^^^^^^^^^^ [*]
>>
>> Not sure if we should leave the lock at this point of time, as we
>> haven't enabled boost until now.
>
> The problem here is with the cpufreq_driver->set_boost() call.
>
> I tried to avoid acquiring lock at one function and release it at
> another (in this case cpufreq_boost_set_sw), especially since the
> __cpufreq_governor() acquires its own lock - good place for deadlock.
>
> Is it OK for you to grab lock at one function
> (cpufreq_boost_trigger_state()) and then at other function
> (cpufreq_boost_set_sw) release it before calling __cpufreq_governor()
> and grab it again after its completion?
>> > + ret = cpufreq_driver->set_boost(state);
>> > + if (ret) {
>> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
>> > + cpufreq_driver->boost_enabled = 0;
>>
>> should be:
>> cpufreq_driver->boost_enabled = !state;
>
> For me = 0 (or = false) is more readable.
> If you wish, I will change it to = !state.
Its not about readability but logic... What if boost was enabled
earlier and we are disabling it now.. and we reach here.. We
need to enable boost again, whereas you are disabling it.
>> > +int cpufreq_boost_supported(void)
>> > +{
>> > + if (cpufreq_driver)
>>
>> This routine is always called from places where cpufreq_driver
>> can't be NULL..
>
> It is also called from thermal. And it happens that thermal is
> initialized earlier.
> Then "NULL pointer dereference" happens.
Ok.. Put a likely() around this check for cpufreq_driver..
> In my opinion at [1] we don't need the if (cpufreq_driver) check.
> But it is up to you to decide.
leave it as is.
> If we agree about above comments, I will post v7 ASAP.
Don't post it ASAP, wait for few more days for others to give
comments.. And also I haven't finished reviewing it until
now.
On 26 July 2013 14:03, Lukasz Majewski <[email protected]> wrote:
> The problem here is with the cpufreq_driver->set_boost() call.
>
> I tried to avoid acquiring lock at one function and release it at
> another (in this case cpufreq_boost_set_sw), especially since the
> __cpufreq_governor() acquires its own lock - good place for deadlock.
>
> Is it OK for you to grab lock at one function
> (cpufreq_boost_trigger_state()) and then at other function
> (cpufreq_boost_set_sw) release it before calling __cpufreq_governor()
> and grab it again after its completion?
Problem is not only that.. but we shouldn't call boost_set() of drivers
like acpi-cpufreq with this lock..... Leave it as it is for now.. Let me see
if I can think of any problems that can happen due to this.
On Fri, 26 Jul 2013 14:54:07 +0530 Viresh Kumar [email protected]
wrote,
> On 26 July 2013 13:39, Lukasz Majewski <[email protected]> wrote:
> > On Fri, 26 Jul 2013 12:58:02 +0530 Viresh Kumar wrote,
> >> On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> >> wrote:
> >> > diff --git a/drivers/cpufreq/acpi-cpufreq.c
> >> > b/drivers/cpufreq/acpi-cpufreq.c
> >>
> >> > static void __init acpi_cpufreq_boost_init(void)
> >> > {
> >> > + acpi_cpufreq_driver.boost_supported = false;
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
> >>
> >> Would be better if we do this in else of below if.
> >
> > We need to set boost_supported = false at [*] for the case when:
> > 1. msrs_alloc fails
> > or
> > 2. acpi_cpufreq is built as a module and can be inserted and removed
> > several times. Without [*] we could end up with wrong (not false)
> > initial state.
>
> Hmm.. Now that I see the code again, we don't need to set it to false
> as it is a global variable and this field is already set to false..
Ok, so then I will remove this line [*].
>
> >> > if (boot_cpu_has(X86_FEATURE_CPB) ||
> >> > boot_cpu_has(X86_FEATURE_IDA)) { msrs = msrs_alloc();
> >>
> >>
> >> > @@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
> >> > *iter = &cpb;
> >> > }
> >> > #endif
> >> > + acpi_cpufreq_boost_init();
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [**]
> >>
> >> We are calling it before registering cpufreq driver. Will this have
> >> any complications?
> >
> > When we call [**] after the cpufreq_register_driver [***] we end up
> > with sysfs boost attribute not exported at x86.
> > The boost attribute is exported at [***] only when
> > acpi_cpufreq.boost_supported = true. However support for boost at
> > x86 is evaluated at acpi_cpufreq_boost_init().
>
> I understand why you moved it above cpufreq driver register. I was
> thinking if there can be few side effects of this..
As fair as I've tested it, there weren't any side effects.
Moreover the acpi_cpufreq_boost_init() mostly read state of the HW, so
IMHO can be done before cpufreg_register_driver().
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 15:03:34 +0530 Viresh Kumar wrote,
> On 26 July 2013 14:03, Lukasz Majewski <[email protected]> wrote:
> > On Fri, 26 Jul 2013 12:47:15 +0530 Viresh Kumar wrote,
> >> On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > +int cpufreq_boost_trigger_state(int state)
> >> > +{
> >> > + unsigned long flags;
> >> > + int ret = 0;
> >> > +
> >> > + if (cpufreq_driver->boost_enabled == state)
> >> > + return 0;
> >> > +
> >> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> >> > + cpufreq_driver->boost_enabled = state;
> >> > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > ^^^^^^^^^^^^^^^^^^^^ [*]
> >>
> >> Not sure if we should leave the lock at this point of time, as we
> >> haven't enabled boost until now.
> >
> > The problem here is with the cpufreq_driver->set_boost() call.
> >
> > I tried to avoid acquiring lock at one function and release it at
> > another (in this case cpufreq_boost_set_sw), especially since the
> > __cpufreq_governor() acquires its own lock - good place for
> > deadlock.
> >
> > Is it OK for you to grab lock at one function
> > (cpufreq_boost_trigger_state()) and then at other function
> > (cpufreq_boost_set_sw) release it before calling
> > __cpufreq_governor() and grab it again after its completion?
>
> >> > + ret = cpufreq_driver->set_boost(state);
> >> > + if (ret) {
> >> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> >> > + cpufreq_driver->boost_enabled = 0;
> >>
> >> should be:
> >> cpufreq_driver->boost_enabled = !state;
> >
> > For me = 0 (or = false) is more readable.
> > If you wish, I will change it to = !state.
>
> Its not about readability but logic... What if boost was enabled
> earlier and we are disabling it now.. and we reach here.. We
> need to enable boost again, whereas you are disabling it.
You are right here. I will change this to = !state
>
> >> > +int cpufreq_boost_supported(void)
> >> > +{
> >> > + if (cpufreq_driver)
> >>
> >> This routine is always called from places where cpufreq_driver
> >> can't be NULL..
> >
> > It is also called from thermal. And it happens that thermal is
> > initialized earlier.
> > Then "NULL pointer dereference" happens.
>
> Ok.. Put a likely() around this check for cpufreq_driver..
Ok.
>
> > In my opinion at [1] we don't need the if (cpufreq_driver) check.
> > But it is up to you to decide.
>
> leave it as is.
Ok.
>
> > If we agree about above comments, I will post v7 ASAP.
>
> Don't post it ASAP, wait for few more days for others to give
> comments.. And also I haven't finished reviewing it until
> now.
Ok.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 15:06:45 +0530 Viresh Kumar wrote,
> On 26 July 2013 14:03, Lukasz Majewski <[email protected]> wrote:
> > The problem here is with the cpufreq_driver->set_boost() call.
> >
> > I tried to avoid acquiring lock at one function and release it at
> > another (in this case cpufreq_boost_set_sw), especially since the
> > __cpufreq_governor() acquires its own lock - good place for
> > deadlock.
> >
> > Is it OK for you to grab lock at one function
> > (cpufreq_boost_trigger_state()) and then at other function
> > (cpufreq_boost_set_sw) release it before calling
> > __cpufreq_governor() and grab it again after its completion?
>
> Problem is not only that.. but we shouldn't call boost_set() of
> drivers like acpi-cpufreq with this lock..... Leave it as it is for
> now.. Let me see if I can think of any problems that can happen due
> to this.
Ok. No problem.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> Policies available in a cpufreq framework are now linked together. They are
> accessible via cpufreq_policy_list defined at cpufreq core.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
Looks good but would have been better if you could have moved
existing code to use this infrastructure..
For example, this code in __cpufreq_add_dev()
#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
read_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_online_cpu(sibling) {
---
}
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
> Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
You shouldn't mention Exynos here and must do exynos stuff at the end
in a separate patch. This one must be generic.
> option the software managed boost is enabled. It also selects thermal
> subsystem to be compiled in. Thermal is necessary for disabling boost
> and cooling down the device when overheating detected.
>
> Boost _MUST_NOT_ work without thermal subsystem with properly defined
> overheating temperatures.
>
> This option doesn't affect x86's ACPI hardware managed boost support
> (i.e. Intel, AMD). In this situation boost management is embedded at
> hardware.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v6:
> - CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
> - Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
> added. It depends on ARM_EXYNOS_CPUFREQ options and selects
> EXYNOS_THERMAL with the main boost config [1].
>
> Changes for v5:
> - New patch
>
> drivers/cpufreq/Kconfig | 3 +++
> drivers/cpufreq/Kconfig.arm | 16 ++++++++++++++++
> 2 files changed, 19 insertions(+)
>
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 534fcb8..3f058a3 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -23,6 +23,9 @@ config CPU_FREQ_TABLE
> config CPU_FREQ_GOV_COMMON
> bool
>
> +config CPU_FREQ_BOOST_SW
> + bool
Invisible is fine but this must be disabled by default and must
depend on thermal, rather than moving dependency on platform's
config.
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
> index 9ae1871..175172d9 100644
> --- a/drivers/cpufreq/exynos-cpufreq.c
> +++ b/drivers/cpufreq/exynos-cpufreq.c
> @@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
>
> static struct freq_attr *exynos_cpufreq_attr[] = {
> &cpufreq_freq_attr_scaling_available_freqs,
> +#ifdef CONFIG_CPU_FREQ_BOOST_SW
Use ARM_EXYNOS_CPU_FREQ_BOOST_SW instead.
> + &cpufreq_freq_attr_scaling_boost_freqs,
> +#endif
> NULL,
> };
>
> @@ -332,6 +335,9 @@ static int __init exynos_cpufreq_probe(struct platform_device *pdev)
>
> locking_frequency = exynos_getspeed(0);
>
> +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> + exynos_driver.boost_supported = true;
> +#endif
So, why here and not in the definition of exynos_driver?
> register_pm_notifier(&exynos_cpufreq_nb);
>
> if (cpufreq_register_driver(&exynos_driver)) {
> --
> 1.7.10.4
>
On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to include
> common code.
>
> Important design decisions:
> - Boost related code is compiled-in unconditionally to cpufreq core and
> disabled by default. The cpufreq_driver is responsibile for setting
> boost_supported flag and providing set_boost callback(if HW support
> is needed). For software managed boost, special Kconfig flag -
> CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
> when a target platform has thermal framework properly configured.
>
> - struct cpufreq_driver has been extended with boost related fields:
> -- boost_supported - when driver supports boosting
> -- boost_enabled - boost state
> -- set_boost - callback to function, which is necessary to
> enable/disable boost
>
> - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
> _only_ when cpufreq driver supports Boost.
>
> - No special spin_lock for Boost was created. The one from cpufreq core
> was reused.
>
> - All available policies are now stored in a list.
>
> - The Boost code doesn't rely on any policy. When boost state is changed,
> then the policy list is iterated and proper adjustements are done.
>
> - To improve safety level, the thermal framework is also extended to disable
> software boosting, when thermal trip point is reached. Then it starts
> monitoring target temperature to evaluate if boost can be enabled
> again. This emulates behaviour similar to HW managed boost (like x86)
>
> New patches for v6:
> cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
>
> Tested at HW:
> Exynos 4412 3.11-rc1 Linux
> Intel Core i7-3770 3.11-rc1 Linux
I am done with review of this patchset now and should say pretty much
comfortable with it now..
On Fri, 26 Jul 2013 15:44:29 +0530 Viresh Kumar [email protected]
wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> > Policies available in a cpufreq framework are now linked together.
> > They are accessible via cpufreq_policy_list defined at cpufreq core.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
>
> Looks good but would have been better if you could have moved
> existing code to use this infrastructure..
>
> For example, this code in __cpufreq_add_dev()
>
> #ifdef CONFIG_HOTPLUG_CPU
> /* Check if this cpu was hot-unplugged earlier and has
> siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags);
> for_each_online_cpu(sibling) {
>
> ---
>
> }
> read_unlock_irqrestore(&cpufreq_driver_lock, flags);
> #endif
Do you mean to write something like:
#ifdef CONFIG_CPU_FREQ_BOOST_SW
write_lock_irqsave(&cpufreq_driver_lock, flags);
list_add(&policy->policy_list, &cpufreq_policy_list);
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
Or Am I missing something?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 26 July 2013 16:28, Lukasz Majewski <[email protected]> wrote:
> On Fri, 26 Jul 2013 15:44:29 +0530 Viresh Kumar [email protected]
> wrote,
>> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>> Looks good but would have been better if you could have moved
>> existing code to use this infrastructure..
>>
>> For example, this code in __cpufreq_add_dev()
>>
>> #ifdef CONFIG_HOTPLUG_CPU
>> /* Check if this cpu was hot-unplugged earlier and has
>> siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags);
>> for_each_online_cpu(sibling) {
>>
>> ---
>>
>> }
>> read_unlock_irqrestore(&cpufreq_driver_lock, flags);
>> #endif
>
> Do you mean to write something like:
>
> #ifdef CONFIG_CPU_FREQ_BOOST_SW
> write_lock_irqsave(&cpufreq_driver_lock, flags);
> list_add(&policy->policy_list, &cpufreq_policy_list);
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> #endif
>
> Or Am I missing something?
I can't imaging how you though I am saying this :)
The code I mentioned actually requires to iterate through the
list of available policies but was iterating over all online cpus..
And so your new infrastructure or this list can be used instead
of looping for all cpus.
On Fri, 26 Jul 2013 15:54:56 +0530 Viresh Kumar wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> > For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been
> > added. Only after selecting "EXYNOS Frequency Overclocking -
> > Software" Kconfig
>
> You shouldn't mention Exynos here and must do exynos stuff at the end
> in a separate patch. This one must be generic.
Please see below comments.
>
> > option the software managed boost is enabled. It also selects
> > thermal subsystem to be compiled in. Thermal is necessary for
> > disabling boost and cooling down the device when overheating
> > detected.
> >
> > Boost _MUST_NOT_ work without thermal subsystem with properly
> > defined overheating temperatures.
> >
> > This option doesn't affect x86's ACPI hardware managed boost support
> > (i.e. Intel, AMD). In this situation boost management is embedded at
> > hardware.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > ---
> > Changes for v6:
> > - CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
> > - Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has
> > been added. It depends on ARM_EXYNOS_CPUFREQ options and selects
> > EXYNOS_THERMAL with the main boost config [1].
> >
> > Changes for v5:
> > - New patch
> >
> > drivers/cpufreq/Kconfig | 3 +++
> > drivers/cpufreq/Kconfig.arm | 16 ++++++++++++++++
> > 2 files changed, 19 insertions(+)
> >
> > diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> > index 534fcb8..3f058a3 100644
> > --- a/drivers/cpufreq/Kconfig
> > +++ b/drivers/cpufreq/Kconfig
> > @@ -23,6 +23,9 @@ config CPU_FREQ_TABLE
> > config CPU_FREQ_GOV_COMMON
> > bool
> >
> > +config CPU_FREQ_BOOST_SW
> > + bool
>
> Invisible is fine but this must be disabled by default and must
> depend on thermal, rather than moving dependency on platform's
> config.
The CPU_FREQ_BOOST_SW [1] is a generic flag (invisible).
I will add "default n" to it.
It shall be used at all BOOST dependent #ifdefs (generic + platform).
Also I've introduced the ARM_EXYNOS_CPU_FREQ_BOOST_SW [2] config
option. The CPU_FREQ_BOOST_SW option is selected from it.
Moreover the [2] depends on ARM_EXYNOS_CPUFREQ (which prevents from
accidental enable/disable). And it selects automatically the
EXYNOS_THERMAL, which is much better than depending only on THERMAL [3]
(the generic framework).
Depending only on [3], results at situation where SW BOOST can be
enabled at x86 or ARM target with only generic THERMAL support (which
doesn't protect from overheating).
So the proposed solution:
1. Defines global flag [1]
2. This flag is selected only when dependencies for more HW close flag
[2] are meet.
3. It is more natural to have Kconfig BOOST enable/disable checkbox at
platform cpufreq driver (with description closer to HW).
4. Other ARCHs can easily define similar to [2] flag and by it select
[1].
For me the approach proposed in this patch is more natural and provides
high protection level from accidental SW boost enable.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 15:56:53 +0530 Viresh Kumar wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>
> > diff --git a/drivers/cpufreq/exynos-cpufreq.c
> > b/drivers/cpufreq/exynos-cpufreq.c index 9ae1871..175172d9 100644
> > --- a/drivers/cpufreq/exynos-cpufreq.c
> > +++ b/drivers/cpufreq/exynos-cpufreq.c
> > @@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct
> > cpufreq_policy *policy)
> >
> > static struct freq_attr *exynos_cpufreq_attr[] = {
> > &cpufreq_freq_attr_scaling_available_freqs,
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>
> Use ARM_EXYNOS_CPU_FREQ_BOOST_SW instead.
For the reasons explained at [PATCH v6 5/8] I would prefer to leave [*]
here.
>
> > + &cpufreq_freq_attr_scaling_boost_freqs,
> > +#endif
> > NULL,
> > };
> >
> > @@ -332,6 +335,9 @@ static int __init exynos_cpufreq_probe(struct
> > platform_device *pdev)
> >
> > locking_frequency = exynos_getspeed(0);
> >
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> > + exynos_driver.boost_supported = true;
> > +#endif
>
> So, why here and not in the definition of exynos_driver?
Right. I will move this to struct cpufreq_driver exynos_driver.
>
> > register_pm_notifier(&exynos_cpufreq_nb);
> >
> > if (cpufreq_register_driver(&exynos_driver)) {
> > --
> > 1.7.10.4
> >
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Friday, July 26, 2013 10:33:21 AM Lukasz Majewski wrote:
> On Fri, 26 Jul 2013 12:47:15 +0530 Viresh Kumar wrote,
> > On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
> > > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> >
> > > /*********************************************************************
> > > + *
> > > BOOST *
> > > +
> > > *********************************************************************/
> > > +static int cpufreq_boost_set_sw(int state) +{
> > > + struct cpufreq_frequency_table *freq_table;
> > > + struct cpufreq_policy *policy;
> > > + int ret = -EINVAL;
> > > +
> > > + list_for_each_entry(policy, &cpufreq_policy_list,
> > > policy_list) {
> > > + freq_table =
> > > cpufreq_frequency_get_table(policy->cpu);
> > > + if (freq_table) {
> > > + ret =
> > > cpufreq_frequency_table_cpuinfo(policy,
> > > + freq_table);
> > > + if (!ret) {
> > > + policy->user_policy.max =
> > > policy->max;
> > > + __cpufreq_governor(policy,
> > > CPUFREQ_GOV_LIMITS);
> > > + }
> > > + }
> > > + }
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +int cpufreq_boost_trigger_state(int state)
> > > +{
> > > + unsigned long flags;
> > > + int ret = 0;
> > > +
> > > + if (cpufreq_driver->boost_enabled == state)
> > > + return 0;
> > > +
> > > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > > + cpufreq_driver->boost_enabled = state;
> > > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> ^^^^^^^^^^^^^^^^^^^^ [*]
> >
> > Not sure if we should leave the lock at this point of time, as we
> > haven't enabled boost until now.
>
> The problem here is with the cpufreq_driver->set_boost() call.
>
> I tried to avoid acquiring lock at one function and release it at
> another (in this case cpufreq_boost_set_sw), especially since the
> __cpufreq_governor() acquires its own lock - good place for deadlock.
>
> Is it OK for you to grab lock at one function
> (cpufreq_boost_trigger_state()) and then at other function
> (cpufreq_boost_set_sw) release it before calling __cpufreq_governor()
> and grab it again after its completion?
It generally is better to avoid doing that, although it is not unheard of.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Fri, 26 Jul 2013 16:32:34 +0530 Viresh Kumar [email protected]
wrote,
> On 26 July 2013 16:28, Lukasz Majewski <[email protected]> wrote:
> > On Fri, 26 Jul 2013 15:44:29 +0530 Viresh Kumar
> > [email protected] wrote,
> >> On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> Looks good but would have been better if you could have moved
> >> existing code to use this infrastructure..
> >>
> >> For example, this code in __cpufreq_add_dev()
> >>
> >> #ifdef CONFIG_HOTPLUG_CPU
> >> /* Check if this cpu was hot-unplugged earlier and has
> >> siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags);
> >> for_each_online_cpu(sibling) {
> >>
> >> ---
> >>
> >> }
> >> read_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >> #endif
> >
> > Do you mean to write something like:
> >
> > #ifdef CONFIG_CPU_FREQ_BOOST_SW
> > write_lock_irqsave(&cpufreq_driver_lock, flags);
> > list_add(&policy->policy_list, &cpufreq_policy_list);
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > #endif
> >
> > Or Am I missing something?
>
> I can't imaging how you though I am saying this :)
>
:-)
> The code I mentioned actually requires to iterate through the
> list of available policies but was iterating over all online cpus..
>
> And so your new infrastructure or this list can be used instead
> of looping for all cpus.
So instead of reading policies from per_cpu variables for all online
cpus, you think of using the list explicitly.
Good idea, but can we first finish the boost patches? Such change can
be applied on top of boost patch series as well.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 14:36:08 +0200 Rafael J. Wysocki [email protected] wrote,
> On Friday, July 26, 2013 10:33:21 AM Lukasz Majewski wrote:
> > On Fri, 26 Jul 2013 12:47:15 +0530 Viresh Kumar wrote,
> > > On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> > > wrote:
> > > > diff --git a/drivers/cpufreq/cpufreq.c
> > > > b/drivers/cpufreq/cpufreq.c
> > >
> > > > /*********************************************************************
> > > > + *
> > > > BOOST *
> > > > +
> > > > *********************************************************************/
> > > > +static int cpufreq_boost_set_sw(int state) +{
> > > > + struct cpufreq_frequency_table *freq_table;
> > > > + struct cpufreq_policy *policy;
> > > > + int ret = -EINVAL;
> > > > +
> > > > + list_for_each_entry(policy, &cpufreq_policy_list,
> > > > policy_list) {
> > > > + freq_table =
> > > > cpufreq_frequency_get_table(policy->cpu);
> > > > + if (freq_table) {
> > > > + ret =
> > > > cpufreq_frequency_table_cpuinfo(policy,
> > > > +
> > > > freq_table);
> > > > + if (!ret) {
> > > > + policy->user_policy.max =
> > > > policy->max;
> > > > + __cpufreq_governor(policy,
> > > > CPUFREQ_GOV_LIMITS);
> > > > + }
> > > > + }
> > > > + }
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > +int cpufreq_boost_trigger_state(int state)
> > > > +{
> > > > + unsigned long flags;
> > > > + int ret = 0;
> > > > +
> > > > + if (cpufreq_driver->boost_enabled == state)
> > > > + return 0;
> > > > +
> > > > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > > > + cpufreq_driver->boost_enabled = state;
> > > > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > ^^^^^^^^^^^^^^^^^^^^ [*]
> > >
> > > Not sure if we should leave the lock at this point of time, as we
> > > haven't enabled boost until now.
> >
> > The problem here is with the cpufreq_driver->set_boost() call.
> >
> > I tried to avoid acquiring lock at one function and release it at
> > another (in this case cpufreq_boost_set_sw), especially since the
> > __cpufreq_governor() acquires its own lock - good place for
> > deadlock.
> >
> > Is it OK for you to grab lock at one function
> > (cpufreq_boost_trigger_state()) and then at other function
> > (cpufreq_boost_set_sw) release it before calling
> > __cpufreq_governor() and grab it again after its completion?
>
> It generally is better to avoid doing that, although it is not
> unheard of.
In this particular case, one also needs to pass the "flags" parameter to
the set_boost() function. This looks a bit unnatural to mix lock layer
with the boost.
>
> Thanks,
> Rafael
>
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 26 July 2013 16:51, Lukasz Majewski <[email protected]> wrote:
> On Fri, 26 Jul 2013 15:54:56 +0530 Viresh Kumar wrote,
>> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>> > +config CPU_FREQ_BOOST_SW
>> > + bool
>>
>> Invisible is fine but this must be disabled by default and must
>> depend on thermal, rather than moving dependency on platform's
>> config.
>
> The CPU_FREQ_BOOST_SW [1] is a generic flag (invisible).
>
> I will add "default n" to it.
Leave it.. We don't need it now.. that's how these kind of config options
are defined as they are disabled by default.
> Depending only on [3], results at situation where SW BOOST can be
> enabled at x86 or ARM target with only generic THERMAL support (which
> doesn't protect from overheating).
I had a similar concern.. Currently also we aren't stopping anybody to
enable boost. By selecting thermal from CPU_FREQ_BOOST_SW, atleast
we are communicating this very well to developers that they need
something else as well. And currently we only have thermal as a source
for telling when to block boost but it can be something else too..
I never said, don't use EXYNOS_THERMAL, its good to have a
dependency on it in the Exynos specific config for boost, but I wanted
normal sw boost also to depend on thermal..
On 26 July 2013 16:56, Lukasz Majewski <[email protected]> wrote:
> On Fri, 26 Jul 2013 15:56:53 +0530 Viresh Kumar wrote,
>> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>>
>> > diff --git a/drivers/cpufreq/exynos-cpufreq.c
>> > b/drivers/cpufreq/exynos-cpufreq.c index 9ae1871..175172d9 100644
>> > --- a/drivers/cpufreq/exynos-cpufreq.c
>> > +++ b/drivers/cpufreq/exynos-cpufreq.c
>> > @@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct
>> > cpufreq_policy *policy)
>> >
>> > static struct freq_attr *exynos_cpufreq_attr[] = {
>> > &cpufreq_freq_attr_scaling_available_freqs,
>> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> ^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
>>
>> Use ARM_EXYNOS_CPU_FREQ_BOOST_SW instead.
>
> For the reasons explained at [PATCH v6 5/8] I would prefer to leave [*]
> here.
I don't see how that reasoning fit here.
This is exynos code and you must use exynos specific boost Kconfig
option here.. Otherwise It might be enabled without Exynos specific option,
if somebody else has selected CONFIG_CPU_FREQ_BOOST_SW in
a multi platform kernel,
On 26 July 2013 18:16, Lukasz Majewski <[email protected]> wrote:
> So instead of reading policies from per_cpu variables for all online
> cpus, you think of using the list explicitly.
>
> Good idea, but can we first finish the boost patches? Such change can
> be applied on top of boost patch series as well.
Its not a problem where we do it. But making sure that we do it :)
If you need to resend this patchset, then that list can be used at the
place I just highlighted.. Change isn't big and so shouldn't be a problem.
Otherwise it might get missed by both of us.
On Fri, 26 Jul 2013 15:06:45 +0530 Viresh Kumar [email protected]
wrote,
> On 26 July 2013 14:03, Lukasz Majewski <[email protected]> wrote:
> > The problem here is with the cpufreq_driver->set_boost() call.
> >
> > I tried to avoid acquiring lock at one function and release it at
> > another (in this case cpufreq_boost_set_sw), especially since the
> > __cpufreq_governor() acquires its own lock - good place for
> > deadlock.
> >
> > Is it OK for you to grab lock at one function
> > (cpufreq_boost_trigger_state()) and then at other function
> > (cpufreq_boost_set_sw) release it before calling
> > __cpufreq_governor() and grab it again after its completion?
>
> Problem is not only that.. but we shouldn't call boost_set() of
> drivers like acpi-cpufreq with this lock..... Leave it as it is for
> now.. Let me see if I can think of any problems that can happen due
> to this.
Do you have any second thoughts about this? Shall I leave it as it is
now?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 August 2013 14:37, Lukasz Majewski <[email protected]> wrote:
> Do you have any second thoughts about this? Shall I leave it as it is
> now?
Honestly speaking I didn't had a chance to look into this..
Leave it as is, in case there is some problem we can patch it later.
On Fri, 26 Jul 2013 14:54:07 +0530 Viresh Kumar [email protected]
wrote,
> On 26 July 2013 13:39, Lukasz Majewski <[email protected]> wrote:
> > On Fri, 26 Jul 2013 12:58:02 +0530 Viresh Kumar wrote,
> >> On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> >> wrote:
> >> > diff --git a/drivers/cpufreq/acpi-cpufreq.c
> >> > b/drivers/cpufreq/acpi-cpufreq.c
> >>
> >> > static void __init acpi_cpufreq_boost_init(void)
> >> > {
> >> > + acpi_cpufreq_driver.boost_supported = false;
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [*]
> >>
> >> Would be better if we do this in else of below if.
> >
> > We need to set boost_supported = false at [*] for the case when:
> > 1. msrs_alloc fails
> > or
> > 2. acpi_cpufreq is built as a module and can be inserted and removed
> > several times. Without [*] we could end up with wrong (not false)
> > initial state.
>
> Hmm.. Now that I see the code again, we don't need to set it to false
> as it is a global variable and this field is already set to false..
Ok, I will delete the line at [*].
>
> >> > if (boot_cpu_has(X86_FEATURE_CPB) ||
> >> > boot_cpu_has(X86_FEATURE_IDA)) { msrs = msrs_alloc();
> >>
> >>
> >> > @@ -1021,12 +995,11 @@ static int __init acpi_cpufreq_init(void)
> >> > *iter = &cpb;
> >> > }
> >> > #endif
> >> > + acpi_cpufreq_boost_init();
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [**]
> >>
> >> We are calling it before registering cpufreq driver. Will this have
> >> any complications?
> >
> > When we call [**] after the cpufreq_register_driver [***] we end up
> > with sysfs boost attribute not exported at x86.
> > The boost attribute is exported at [***] only when
> > acpi_cpufreq.boost_supported = true. However support for boost at
> > x86 is evaluated at acpi_cpufreq_boost_init().
>
> I understand why you moved it above cpufreq driver register. I was
> thinking if there can be few side effects of this..
Have any problem with the above change came to your mind?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 August 2013 14:42, Lukasz Majewski <[email protected]> wrote:
> Have any problem with the above change came to your mind?
No.
Dear Zhang, Eduardo,
> This patch provides auto disable/enable operation for boost. When any
> defined trip point is passed, the boost is disabled.
> In that moment thermal monitor workqueue is woken up and it monitors
> if the device temperature drops below 75% of the smallest trip point.
> When device cools down, the boost is enabled again.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v6:
> - Disable boost only when supported and enabled
> - Protect boost related thermal_zone_device struct fields with mutex
> - Evaluate temperature trend during boost enable decision
> - Create separate methods to handle boost enable/disable
> (thermal_boost_{enable|disable}) operations
> - Boost is disabled at any trip point passage (not only the non
> critical one)
> - Add stub definitions for cpufreq boost functions used when
> CONFIG_CPU_FREQ is NOT defined.
>
> Changes for v5:
> - Move boost disable code from cpu_cooling.c to thermal_core.c
> (to handle_non_critical_trips)
> - Extent struct thermal_zone_device by adding overheated bool flag
> - Implement auto enable of boost after device cools down
> - Introduce boost_polling flag, which indicates if thermal uses it's
> predefined pool delay or has woken up thermal workqueue only to wait
> until device cools down.
>
> Changes for v4:
> - New patch
>
ping...
> drivers/thermal/thermal_core.c | 55
> ++++++++++++++++++++++++++++++++++++++++
> include/linux/cpufreq.h | 15 +++++++++++
> include/linux/thermal.h | 2 ++ 3 files changed, 72
> insertions(+)
>
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c index 1f02e8e..8f4be55 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -34,6 +34,7 @@
> #include <linux/thermal.h>
> #include <linux/reboot.h>
> #include <linux/string.h>
> +#include <linux/cpufreq.h>
> #include <net/netlink.h>
> #include <net/genetlink.h>
>
> @@ -354,9 +355,59 @@ static void handle_critical_trips(struct
> thermal_zone_device *tz, }
> }
>
> +static int thermal_boost_enable(struct thermal_zone_device *tz)
> +{
> + enum thermal_trend trend = get_tz_trend(tz, 0);
> + long trip_temp;
> +
> + if (!tz->ops->get_trip_temp || !tz->overheated)
> + return -EPERM;
> + if (trend == THERMAL_TREND_RAISING || trend ==
> THERMAL_TREND_RAISE_FULL)
> + return -EBUSY;
> +
> + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> + /*
> + * Enable boost again only when current temperature is less
> + * than 75% of trip_temp[0]
> + */
> + if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
> + mutex_lock(&tz->lock);
> + tz->overheated = false;
> + if (tz->boost_polling) {
> + tz->boost_polling = false;
> + tz->polling_delay = 0;
> + }
> + mutex_unlock(&tz->lock);
> + cpufreq_boost_trigger_state(1);
> + return 0;
> + }
> + return -EBUSY;
> +}
> +
> +static void thermal_boost_disable(struct thermal_zone_device *tz)
> +{
> + cpufreq_boost_trigger_state(0);
> +
> + /*
> + * If no workqueue for monitoring is running - start one with
> + * 1000 ms monitoring period
> + * If workqueue already running - do not change its period
> and only
> + * test if target CPU has cooled down
> + */
> + mutex_lock(&tz->lock);
> + if (!tz->polling_delay) {
> + tz->boost_polling = true;
> + tz->polling_delay = 1000;
> + }
> + tz->overheated = true;
> + mutex_unlock(&tz->lock);
> +}
> +
> static void handle_thermal_trip(struct thermal_zone_device *tz, int
> trip) {
> enum thermal_trip_type type;
> + if (cpufreq_boost_supported() && cpufreq_boost_enabled())
> + thermal_boost_disable(tz);
>
> tz->ops->get_trip_type(tz, trip, &type);
>
> @@ -455,6 +506,10 @@ static void thermal_zone_device_check(struct
> work_struct *work) struct thermal_zone_device *tz =
> container_of(work, struct thermal_zone_device,
> poll_queue.work);
> + if (cpufreq_boost_supported())
> + if (!thermal_boost_enable(tz))
> + return;
> +
> thermal_zone_device_update(tz);
> }
>
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 49a73c9..3d9276d 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -435,9 +435,24 @@ int cpufreq_frequency_table_target(struct
> cpufreq_policy *policy, unsigned int relation,
> unsigned int *index);
>
> +#ifdef CONFIG_CPU_FREQ
> int cpufreq_boost_trigger_state(int state);
> int cpufreq_boost_supported(void);
> int cpufreq_boost_enabled(void);
> +#else
> +static inline int cpufreq_boost_trigger_state(int state)
> +{
> + return 0;
> +}
> +static inline int cpufreq_boost_supported(void)
> +{
> + return 0;
> +}
> +static inline int cpufreq_boost_enabled(void)
> +{
> + return 0;
> +}
> +#endif
> /* the following 3 funtions are for cpufreq core use only */
> struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned
> int cpu);
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index a386a1c..f1aa3c2 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -172,6 +172,8 @@ struct thermal_zone_device {
> int emul_temperature;
> int passive;
> unsigned int forced_passive;
> + bool overheated;
> + bool boost_polling;
> const struct thermal_zone_device_ops *ops;
> const struct thermal_zone_params *tzp;
> struct thermal_governor *governor;
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Fri, 26 Jul 2013 15:56:53 +0530 Viresh Kumar [email protected]
wrote,
> On 25 July 2013 22:03, Lukasz Majewski <[email protected]> wrote:
>
> > diff --git a/drivers/cpufreq/exynos-cpufreq.c
> > b/drivers/cpufreq/exynos-cpufreq.c index 9ae1871..175172d9 100644
> > --- a/drivers/cpufreq/exynos-cpufreq.c
> > +++ b/drivers/cpufreq/exynos-cpufreq.c
> > @@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct
> > cpufreq_policy *policy)
> >
> > static struct freq_attr *exynos_cpufreq_attr[] = {
> > &cpufreq_freq_attr_scaling_available_freqs,
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
>
> Use ARM_EXYNOS_CPU_FREQ_BOOST_SW instead.
Ok, the ARM_EXYNOS_CPU_FREQ_BOOST_SW looks more appropriate here.
>
> > + &cpufreq_freq_attr_scaling_boost_freqs,
> > +#endif
> > NULL,
> > };
> >
> > @@ -332,6 +335,9 @@ static int __init exynos_cpufreq_probe(struct
> > platform_device *pdev)
> >
> > locking_frequency = exynos_getspeed(0);
> >
> > +#ifdef CONFIG_CPU_FREQ_BOOST_SW
> > + exynos_driver.boost_supported = true;
> > +#endif
>
> So, why here and not in the definition of exynos_driver?
Ok, I will move the above code to struct cpufreq_driver exynos_driver
>
> > register_pm_notifier(&exynos_cpufreq_nb);
> >
> > if (cpufreq_register_driver(&exynos_driver)) {
> > --
> > 1.7.10.4
> >
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Mon, 29 Jul 2013 12:28:02 +0530 Viresh Kumar [email protected]
wrote,
> On 26 July 2013 16:51, Lukasz Majewski <[email protected]> wrote:
> > On Fri, 26 Jul 2013 15:54:56 +0530 Viresh Kumar wrote,
> >> On 25 July 2013 22:03, Lukasz Majewski <[email protected]>
> >> wrote:
>
> >> > +config CPU_FREQ_BOOST_SW
> >> > + bool
> >>
> >> Invisible is fine but this must be disabled by default and must
> >> depend on thermal, rather than moving dependency on platform's
> >> config.
> >
> > The CPU_FREQ_BOOST_SW [1] is a generic flag (invisible).
> >
> > I will add "default n" to it.
>
> Leave it.. We don't need it now.. that's how these kind of config
> options are defined as they are disabled by default.
Ok. Please see below proposition.
>
> > Depending only on [3], results at situation where SW BOOST can be
> > enabled at x86 or ARM target with only generic THERMAL support
> > (which doesn't protect from overheating).
>
> I had a similar concern.. Currently also we aren't stopping anybody to
> enable boost. By selecting thermal from CPU_FREQ_BOOST_SW, atleast
> we are communicating this very well to developers that they need
> something else as well. And currently we only have thermal as a source
> for telling when to block boost but it can be something else too..
>
> I never said, don't use EXYNOS_THERMAL, its good to have a
> dependency on it in the Exynos specific config for boost, but I wanted
> normal sw boost also to depend on thermal..
1. at ./drivers/cpufreq/Kconfig:
+config CPU_FREQ_BOOST_SW
+ bool
+ depends on THERMAL
2. at ./drivers/cpufreq/Kconfig.arm:
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ default n
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with
properly
+ defined trip points.
+
+ If in doubt, say N.
+
Shall I split this patch to two (1. and 2.) or leave it as a single one?
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 12 August 2013 15:56, Lukasz Majewski <[email protected]> wrote:
> 1. at ./drivers/cpufreq/Kconfig:
>
> +config CPU_FREQ_BOOST_SW
> + bool
> + depends on THERMAL
>
> 2. at ./drivers/cpufreq/Kconfig.arm:
>
> +config ARM_EXYNOS_CPU_FREQ_BOOST_SW
> + bool "EXYNOS Frequency Overclocking - Software"
> + depends on ARM_EXYNOS_CPUFREQ
> + select CPU_FREQ_BOOST_SW
> + select EXYNOS_THERMAL
> + default n
> + help
> + This driver supports software managed overclocking (BOOST).
> + It allows usage of special frequencies for Samsung Exynos
> + processors if thermal conditions are appropriate.
> +
> + It reguires, for safe operation, thermal framework with
> properly
> + defined trip points.
> +
> + If in doubt, say N.
> +
>
> Shall I split this patch to two (1. and 2.) or leave it as a single one?
Looks fine.. Keep it in a single patch.
On Mon, 12 Aug 2013 15:58:12 +0530 Viresh Kumar [email protected]
wrote,
> On 12 August 2013 15:56, Lukasz Majewski <[email protected]>
> wrote:
> > 1. at ./drivers/cpufreq/Kconfig:
> >
> > +config CPU_FREQ_BOOST_SW
> > + bool
> > + depends on THERMAL
> >
> > 2. at ./drivers/cpufreq/Kconfig.arm:
> >
> > +config ARM_EXYNOS_CPU_FREQ_BOOST_SW
> > + bool "EXYNOS Frequency Overclocking - Software"
> > + depends on ARM_EXYNOS_CPUFREQ
> > + select CPU_FREQ_BOOST_SW
> > + select EXYNOS_THERMAL
> > + default n
^^^^^^^^^^^^^^^^ I will also remove this line.
> > + help
> > + This driver supports software managed overclocking
> > (BOOST).
> > + It allows usage of special frequencies for Samsung Exynos
> > + processors if thermal conditions are appropriate.
> > +
> > + It reguires, for safe operation, thermal framework with
> > properly
> > + defined trip points.
> > +
> > + If in doubt, say N.
> > +
> >
> > Shall I split this patch to two (1. and 2.) or leave it as a single
> > one?
>
> Looks fine.. Keep it in a single patch.
Ok.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing set_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- boost_enabled - boost state
-- set_boost - callback to function, which is necessary to
enable/disable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
Tested at HW:
Exynos 4412 3.11-rc4 Linux
Intel Core i7-3770 3.11-rc4 Linux
Above patches were posted on top of linux_pm/linux-next with following
patches applied:
cpufreq: exynos5440: Fix to skip when new frequency same as current
cpufreq: fix EXYNOS drivers selection
Lukasz Majewski (7):
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Provide support for software managed BOOST
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
Documentation:cpufreq:boost: Update BOOST documentation
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Documentation/cpu-freq/boost.txt | 26 ++++----
drivers/cpufreq/Kconfig | 4 ++
drivers/cpufreq/Kconfig.arm | 15 +++++
drivers/cpufreq/acpi-cpufreq.c | 86 +++++++++----------------
drivers/cpufreq/cpufreq.c | 115 +++++++++++++++++++++++++++++++++-
drivers/cpufreq/exynos-cpufreq.c | 6 ++
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 53 +++++++++++++---
drivers/thermal/thermal_core.c | 55 ++++++++++++++++
include/linux/cpufreq.h | 26 +++++++-
include/linux/thermal.h | 2 +
11 files changed, 310 insertions(+), 80 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency
above its normal operation limits. Such mode shall be only used for a
short time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) overclocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code. By default boost is disabled. One global
attribute is available at: /sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with a proper call
to sysfs.
The cpufreq_boost_trigger_state() function is defined non static on purpose.
It is used later with thermal subsystem to provide automatic enable/disable
of the BOOST feature.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- Properly change cpufreq_driver->boost_enabled when set_boost() fails
(=0 to =!state)
- Add likely() around cpufreq_driver
- Remove parenthesis around boost.attr
Changes for v6:
- Remove sysfs boost attribute when subsys_iterface_unregister() fails
- Move global boost_enabled variable from cpufreq.c to platform dependent
struct cpufreq_driver
- pr_err() message is also printed when boost disable fails
- Call __cpufreq_governor() to force recalculation of next frequency when
boost is triggered. It is needed with i.e. performance class of governors
- Change cpufreq_boost_enable_sw() -> cpufreq_boost_set_sw()
- Rename .enable_boost function pointer to .set_boost
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 115 +++++++++++++++++++++++++++++++++++++++++-
drivers/cpufreq/freq_table.c | 53 ++++++++++++++++---
include/linux/cpufreq.h | 10 ++++
3 files changed, 170 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 37a6874..196d8e8 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -345,6 +345,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %s BOOST!\n", __func__,
+ enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -2036,6 +2063,70 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_set_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (!ret) {
+ policy->user_policy.max = policy->max;
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (cpufreq_driver->boost_enabled == state)
+ return 0;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ ret = cpufreq_driver->set_boost(state);
+ if (ret) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = !state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_err("%s: Cannot %s BOOST\n", __func__,
+ state ? "enabled" : "disabled");
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (likely(cpufreq_driver))
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return cpufreq_driver->boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2074,9 +2165,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_boost_supported()) {
+ /*
+ * Check if driver provides function to enable boost -
+ * if not, use cpufreq_boost_set_sw as default
+ */
+ if (!cpufreq_driver->set_boost)
+ cpufreq_driver->set_boost = cpufreq_boost_set_sw;
+
+ ret = cpufreq_sysfs_create_file(&boost.attr);
+ if (ret) {
+ pr_err("%s: cannot register global BOOST sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
- goto err_null_driver;
+ goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
@@ -2103,6 +2210,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_boost_unreg:
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2129,6 +2239,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
down_write(&cpufreq_rwsem);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f111454a..d7eed63 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -169,7 +173,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ bool show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -184,6 +189,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq
+ * display BOOST freqs
+ *
+ * show_boost = false and driver_data = BOOST freq
+ * show_boost = true and driver_data != BOOST freq
+ * continue - do not display anything
+ *
+ * show_boost = false and driver_data != BOOST freq
+ * display NON BOOST freqs
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -192,14 +211,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, false);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, true);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d568f39..b5defd4 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -209,6 +209,11 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost) (int state);
};
/* flags */
@@ -381,6 +386,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+#define CPUFREQ_BOOST_FREQ ~2
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
@@ -402,12 +408,16 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
/* the following funtion is for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
void cpufreq_frequency_table_put_attr(unsigned int cpu);
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- None
Changes for v6:
- Disable boost only when supported and enabled
- Protect boost related thermal_zone_device struct fields with mutex
- Evaluate temperature trend during boost enable decision
- Create separate methods to handle boost enable/disable
(thermal_boost_{enable|disable}) operations
- Boost is disabled at any trip point passage (not only the non critical one)
- Add stub definitions for cpufreq boost functions used when
CONFIG_CPU_FREQ is NOT defined.
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
include/linux/cpufreq.h | 16 +++++++++++-
include/linux/thermal.h | 2 ++
3 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1f02e8e..8f4be55 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -354,9 +355,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
}
+static int thermal_boost_enable(struct thermal_zone_device *tz)
+{
+ enum thermal_trend trend = get_tz_trend(tz, 0);
+ long trip_temp;
+
+ if (!tz->ops->get_trip_temp || !tz->overheated)
+ return -EPERM;
+ if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
+ return -EBUSY;
+
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ mutex_lock(&tz->lock);
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ }
+ mutex_unlock(&tz->lock);
+ cpufreq_boost_trigger_state(1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void thermal_boost_disable(struct thermal_zone_device *tz)
+{
+ cpufreq_boost_trigger_state(0);
+
+ /*
+ * If no workqueue for monitoring is running - start one with
+ * 1000 ms monitoring period
+ * If workqueue already running - do not change its period and only
+ * test if target CPU has cooled down
+ */
+ mutex_lock(&tz->lock);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ tz->overheated = true;
+ mutex_unlock(&tz->lock);
+}
+
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ if (cpufreq_boost_supported() && cpufreq_boost_enabled())
+ thermal_boost_disable(tz);
tz->ops->get_trip_type(tz, trip, &type);
@@ -455,6 +506,10 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ if (cpufreq_boost_supported())
+ if (!thermal_boost_enable(tz))
+ return;
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index b5defd4..ec19da9 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -408,10 +408,24 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+#ifdef CONFIG_CPU_FREQ
int cpufreq_boost_trigger_state(int state);
int cpufreq_boost_supported(void);
int cpufreq_boost_enabled(void);
-
+#else
+static inline int cpufreq_boost_trigger_state(int state)
+{
+ return 0;
+}
+static inline int cpufreq_boost_supported(void)
+{
+ return 0;
+}
+static inline int cpufreq_boost_enabled(void)
+{
+ return 0;
+}
+#endif
/* the following funtion is for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1c..f1aa3c2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- Remove superfluous acpi_cpufreq_driver.boost_supported = false at
acpi_cpufreq_boost_init()
Changes for v6:
- Perform acpi_cpufreq_boost_init initialization before cpufreq_driver
registration
- Compile store_boost() only when CONFIG_X86_ACPI_CPUFREQ_CPB defined
- Use boost_enabled flag defined at acpi_cpufreq_driver to store information
about boost state
- Instead of using cpufreq_set_boost_enabled(), modify the boost_enable in
the acpi driver code
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 86 ++++++++++++++--------------------------
1 file changed, 29 insertions(+), 57 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 9b5d1b1..4400b89 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
get_online_cpus();
-
boost_set_msrs(val, cpu_online_mask);
-
put_online_cpus();
-
- boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
-}
-
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
+ return 0;
}
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
+static ssize_t store_boost(const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val = 0;
+
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost((int) val);
+
+ return count;
+}
+
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
}
static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
@@ -582,7 +565,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -937,6 +920,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.attr = acpi_cpufreq_attr,
+ .set_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -947,33 +931,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
-
+ acpi_cpufreq_driver.boost_supported = true;
+ acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
+ cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1015,12 +988,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb;
}
#endif
+ acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret)
free_acpi_perf_data();
- else
- acpi_cpufreq_boost_init();
return ret;
}
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
option the software managed boost is enabled. It also selects thermal
subsystem to be compiled in. Thermal is necessary for disabling boost
and cooling down the device when overheating detected.
Boost _MUST_NOT_ work without thermal subsystem with properly defined
overheating temperatures.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- Remove superfluous "default n" definition
- Generic CPU_FREQ_BOOST_SW depends on THERMAL
Changes for v6:
- CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
- Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
added. It depends on ARM_EXYNOS_CPUFREQ options and selects
EXYNOS_THERMAL with the main boost config [1].
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 4 ++++
drivers/cpufreq/Kconfig.arm | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 534fcb8..e3cbf72 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,10 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool
+ depends on THERMAL
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0fa204b..6a6d173 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -67,6 +67,21 @@ config ARM_EXYNOS5440_CPUFREQ
If in doubt, say N.
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly
+ defined trip points.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- None
Changes for v6:
- None
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
frequency, which can be only enabled for BOOST mode.
This frequency shall be used only for limited time, since it might cause
target device to overheat.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- None
Changes for v6:
- New patch
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index e270b42..367f600 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = {
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
--
1.7.10.4
The cpufreq_driver's boost_supported flag is true only when boost
support is explicitly enabled. Boost related attributes are exported only
under the same condition.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v7:
- Replace CONFIG_CPU_FREQ_BOOST_SW with CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
- Move boost_supported initialization to struct cpufreq_driver exynos_driver
Changes for v6:
- Replace exynos_driver.boost_supported = 1 to = true
- Protect boost attributes export with CONFIG_CPU_FREQ_BOOST_SW
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index b9f9aee..2786aba 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ &cpufreq_freq_attr_scaling_boost_freqs,
+#endif
NULL,
};
@@ -282,6 +285,9 @@ static struct cpufreq_driver exynos_driver = {
.exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
.attr = exynos_cpufreq_attr,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ .boost_supported = true,
+#endif
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
--
1.7.10.4
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to include
> common code.
>
> Important design decisions:
> - Boost related code is compiled-in unconditionally to cpufreq core and
> disabled by default. The cpufreq_driver is responsibile for setting
> boost_supported flag and providing set_boost callback(if HW support
> is needed). For software managed boost, special Kconfig flag -
> CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
> when a target platform has thermal framework properly configured.
>
> - struct cpufreq_driver has been extended with boost related fields:
> -- boost_supported - when driver supports boosting
> -- boost_enabled - boost state
> -- set_boost - callback to function, which is necessary to
> enable/disable boost
>
> - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
> _only_ when cpufreq driver supports Boost.
>
> - No special spin_lock for Boost was created. The one from cpufreq core
> was reused.
>
> - The Boost code doesn't rely on any policy. When boost state is changed,
> then the policy list is iterated and proper adjustements are done.
>
> - To improve safety level, the thermal framework is also extended to disable
> software boosting, when thermal trip point is reached. Then it starts
> monitoring target temperature to evaluate if boost can be enabled
> again. This emulates behaviour similar to HW managed boost (like x86)
>
> Tested at HW:
> Exynos 4412 3.11-rc4 Linux
> Intel Core i7-3770 3.11-rc4 Linux
>
> Above patches were posted on top of linux_pm/linux-next with following
> patches applied:
>
> cpufreq: exynos5440: Fix to skip when new frequency same as current
> cpufreq: fix EXYNOS drivers selection
>
> Lukasz Majewski (7):
> cpufreq: Add boost frequency support in core
> cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
> boost solution
> thermal:boost: Automatic enable/disable of BOOST feature
> cpufreq:boost:Kconfig: Provide support for software managed BOOST
> cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> framework
> Documentation:cpufreq:boost: Update BOOST documentation
> cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Hi Lukasz,
I haven't found time yet to go through this series.. I want to do a deep/careful
review this time as these are almost the final patches.
Will try to get over them by the end of this week..
--
viresh
On Mon, 19 Aug 2013 12:08:26 +0530 Viresh Kumar [email protected]
wrote,
> On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> wrote:
> > This patch series introduces support for CPU overclocking technique
> > called Boost.
> >
> > It is a follow up of a LAB governor proposal. Boost is a LAB
> > component:
> > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> >
> > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > software oriented one (like the one done at Exynos).
> > For this reason cpufreq/freq_table code has been reorganized to
> > include common code.
> >
> > Important design decisions:
> > - Boost related code is compiled-in unconditionally to cpufreq core
> > and disabled by default. The cpufreq_driver is responsibile for
> > setting boost_supported flag and providing set_boost callback(if HW
> > support is needed). For software managed boost, special Kconfig
> > flag - CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be
> > selected only when a target platform has thermal framework properly
> > configured.
> >
> > - struct cpufreq_driver has been extended with boost related fields:
> > -- boost_supported - when driver supports boosting
> > -- boost_enabled - boost state
> > -- set_boost - callback to function, which is necessary to
> > enable/disable boost
> >
> > - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is
> > visible _only_ when cpufreq driver supports Boost.
> >
> > - No special spin_lock for Boost was created. The one from cpufreq
> > core was reused.
> >
> > - The Boost code doesn't rely on any policy. When boost state is
> > changed, then the policy list is iterated and proper adjustements
> > are done.
> >
> > - To improve safety level, the thermal framework is also extended
> > to disable software boosting, when thermal trip point is reached.
> > Then it starts monitoring target temperature to evaluate if boost
> > can be enabled again. This emulates behaviour similar to HW managed
> > boost (like x86)
> >
> > Tested at HW:
> > Exynos 4412 3.11-rc4 Linux
> > Intel Core i7-3770 3.11-rc4 Linux
> >
> > Above patches were posted on top of linux_pm/linux-next with
> > following patches applied:
> >
> > cpufreq: exynos5440: Fix to skip when new frequency same as current
> > cpufreq: fix EXYNOS drivers selection
> >
> > Lukasz Majewski (7):
> > cpufreq: Add boost frequency support in core
> > cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with
> > common boost solution
> > thermal:boost: Automatic enable/disable of BOOST feature
> > cpufreq:boost:Kconfig: Provide support for software managed BOOST
> > cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> > framework
> > Documentation:cpufreq:boost: Update BOOST documentation
> > cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
>
> Hi Lukasz,
>
Hi Viresh,
> I haven't found time yet to go through this series..
I've just started wondering if I had send those patches correctly :-).
> I want to do a
> deep/careful review this time as these are almost the final patches.
Ok.
>
> Will try to get over them by the end of this week..
Ok, I understand.
>
> --
> viresh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Monday, August 19, 2013 08:50:37 AM Lukasz Majewski wrote:
> On Mon, 19 Aug 2013 12:08:26 +0530 Viresh Kumar [email protected]
> wrote,
> > On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> > wrote:
> > > This patch series introduces support for CPU overclocking technique
> > > called Boost.
> > >
> > > It is a follow up of a LAB governor proposal. Boost is a LAB
> > > component:
> > > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> > >
> > > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > > software oriented one (like the one done at Exynos).
> > > For this reason cpufreq/freq_table code has been reorganized to
> > > include common code.
> > >
> > > Important design decisions:
> > > - Boost related code is compiled-in unconditionally to cpufreq core
> > > and disabled by default. The cpufreq_driver is responsibile for
> > > setting boost_supported flag and providing set_boost callback(if HW
> > > support is needed). For software managed boost, special Kconfig
> > > flag - CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be
> > > selected only when a target platform has thermal framework properly
> > > configured.
> > >
> > > - struct cpufreq_driver has been extended with boost related fields:
> > > -- boost_supported - when driver supports boosting
> > > -- boost_enabled - boost state
> > > -- set_boost - callback to function, which is necessary to
> > > enable/disable boost
> > >
> > > - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is
> > > visible _only_ when cpufreq driver supports Boost.
> > >
> > > - No special spin_lock for Boost was created. The one from cpufreq
> > > core was reused.
> > >
> > > - The Boost code doesn't rely on any policy. When boost state is
> > > changed, then the policy list is iterated and proper adjustements
> > > are done.
> > >
> > > - To improve safety level, the thermal framework is also extended
> > > to disable software boosting, when thermal trip point is reached.
> > > Then it starts monitoring target temperature to evaluate if boost
> > > can be enabled again. This emulates behaviour similar to HW managed
> > > boost (like x86)
> > >
> > > Tested at HW:
> > > Exynos 4412 3.11-rc4 Linux
> > > Intel Core i7-3770 3.11-rc4 Linux
> > >
> > > Above patches were posted on top of linux_pm/linux-next with
> > > following patches applied:
> > >
> > > cpufreq: exynos5440: Fix to skip when new frequency same as current
> > > cpufreq: fix EXYNOS drivers selection
> > >
> > > Lukasz Majewski (7):
> > > cpufreq: Add boost frequency support in core
> > > cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with
> > > common boost solution
> > > thermal:boost: Automatic enable/disable of BOOST feature
> > > cpufreq:boost:Kconfig: Provide support for software managed BOOST
> > > cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> > > framework
> > > Documentation:cpufreq:boost: Update BOOST documentation
> > > cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
> >
> > Hi Lukasz,
> >
>
> Hi Viresh,
>
> > I haven't found time yet to go through this series..
>
> I've just started wondering if I had send those patches correctly :-).
>
> > I want to do a
> > deep/careful review this time as these are almost the final patches.
>
> Ok.
>
> >
> > Will try to get over them by the end of this week..
>
> Ok, I understand.
Do I assume correctly that this stuff has been tested on ACPI-compatible x86
with acpi-cpufreq and everything has worked correctly there?
Rafael
On Tue, 20 Aug 2013 01:29:20 +0200 Rafael J. Wysocki [email protected] wrote,
> On Monday, August 19, 2013 08:50:37 AM Lukasz Majewski wrote:
> > On Mon, 19 Aug 2013 12:08:26 +0530 Viresh Kumar
> > [email protected] wrote,
> > > On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> > > wrote:
> > > > This patch series introduces support for CPU overclocking
> > > > technique called Boost.
> > > >
> > > > It is a follow up of a LAB governor proposal. Boost is a LAB
> > > > component:
> > > > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> > > >
> > > > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > > > software oriented one (like the one done at Exynos).
> > > > For this reason cpufreq/freq_table code has been reorganized to
> > > > include common code.
> > > >
> > > > Important design decisions:
> > > > - Boost related code is compiled-in unconditionally to cpufreq
> > > > core and disabled by default. The cpufreq_driver is
> > > > responsibile for setting boost_supported flag and providing
> > > > set_boost callback(if HW support is needed). For software
> > > > managed boost, special Kconfig flag - CONFIG_CPU_FREQ_BOOST_SW
> > > > has been defined. It will be selected only when a target
> > > > platform has thermal framework properly configured.
> > > >
> > > > - struct cpufreq_driver has been extended with boost related
> > > > fields: -- boost_supported - when driver supports boosting
> > > > -- boost_enabled - boost state
> > > > -- set_boost - callback to function, which is necessary
> > > > to enable/disable boost
> > > >
> > > > - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost)
> > > > is visible _only_ when cpufreq driver supports Boost.
> > > >
> > > > - No special spin_lock for Boost was created. The one from
> > > > cpufreq core was reused.
> > > >
> > > > - The Boost code doesn't rely on any policy. When boost state is
> > > > changed, then the policy list is iterated and proper
> > > > adjustements are done.
> > > >
> > > > - To improve safety level, the thermal framework is also
> > > > extended to disable software boosting, when thermal trip point
> > > > is reached. Then it starts monitoring target temperature to
> > > > evaluate if boost can be enabled again. This emulates behaviour
> > > > similar to HW managed boost (like x86)
> > > >
> > > > Tested at HW:
> > > > Exynos 4412 3.11-rc4 Linux
> > > > Intel Core i7-3770 3.11-rc4 Linux
> > > >
> > > > Above patches were posted on top of linux_pm/linux-next with
> > > > following patches applied:
> > > >
> > > > cpufreq: exynos5440: Fix to skip when new frequency same as
> > > > current cpufreq: fix EXYNOS drivers selection
> > > >
> > > > Lukasz Majewski (7):
> > > > cpufreq: Add boost frequency support in core
> > > > cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with
> > > > common boost solution
> > > > thermal:boost: Automatic enable/disable of BOOST feature
> > > > cpufreq:boost:Kconfig: Provide support for software managed
> > > > BOOST cpufreq:exynos:Extend Exynos cpufreq driver to support
> > > > boost framework
> > > > Documentation:cpufreq:boost: Update BOOST documentation
> > > > cpufreq:exynos4x12: Change L0 driver data to
> > > > CPUFREQ_BOOST_FREQ
> > >
> > > Hi Lukasz,
> > >
> >
> > Hi Viresh,
> >
> > > I haven't found time yet to go through this series..
> >
> > I've just started wondering if I had send those patches
> > correctly :-).
> >
> > > I want to do a
> > > deep/careful review this time as these are almost the final
> > > patches.
> >
> > Ok.
> >
> > >
> > > Will try to get over them by the end of this week..
> >
> > Ok, I understand.
>
> Do I assume correctly that this stuff has been tested on
> ACPI-compatible x86 with acpi-cpufreq and everything has worked
> correctly there?
>
> Rafael
>
Hi Rafael,
Following test configuration/test case (x86):
- DELL OptiPlex 9010 Intel Core i7-3770
- Linux repo: [kernel_pm_http/bleeding-edge] [kernel_pm_http/linux-next]
SHA1: a238ea5e20be7bea2b1fc951a024ecce770306b5
with v7 applied on top
- Linux version: 3.11-rc4 (patches v7) and 3.11-rc1 (v6)
- Ubuntu 11.10 (make bzImage + make all when module was needed)
- config_ubuntu_3_11 (the default one for ubuntu)
- KConfig:
1. Disabled intel_pstate driver
2. Enabled ACPI-Prosessor P state driver
3. Legacy cpb sysfs knob support for AMD CPUs ON/OFF (which is a
part of acpi-cpufreq.c driver).
- acpi-cpufreq driver was build as a module or was embedded in kernel
(tested with modprobe -i / -r => no dmesg error|warning output)
- I was able to read/write (echo 0/1
> /sys/devices/system/cpu/cpufreq/boost) => no output at dmesg -
system was working stable.
Toolchain: gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
Since I'm mostly working with ARM (exynos4412) and major work was done
with cpufreq core (and x86 related work was to move common code to
cpufreq core) tests mostly have been performed on ARM.
Tests on ARM:
- Stress tests with up to 4 scripts running to enable/disable boost
sysfs attribute with random time interval (gzip < /dev/urandom
> /dev/null).
- Test to overheat the ARM target and look if boost+thermal cools down
the device and enables boost again.
- LAB governor (which was already posted to ML) to boost when power
envelope allows it.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Tuesday, August 20, 2013 10:11:47 AM Lukasz Majewski wrote:
> On Tue, 20 Aug 2013 01:29:20 +0200 Rafael J. Wysocki [email protected] wrote,
> > On Monday, August 19, 2013 08:50:37 AM Lukasz Majewski wrote:
> > > On Mon, 19 Aug 2013 12:08:26 +0530 Viresh Kumar
> > > [email protected] wrote,
> > > > On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> > > > wrote:
> > > > > This patch series introduces support for CPU overclocking
> > > > > technique called Boost.
> > > > >
> > > > > It is a follow up of a LAB governor proposal. Boost is a LAB
> > > > > component:
> > > > > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> > > > >
> > > > > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > > > > software oriented one (like the one done at Exynos).
> > > > > For this reason cpufreq/freq_table code has been reorganized to
> > > > > include common code.
> > > > >
> > > > > Important design decisions:
> > > > > - Boost related code is compiled-in unconditionally to cpufreq
> > > > > core and disabled by default. The cpufreq_driver is
> > > > > responsibile for setting boost_supported flag and providing
> > > > > set_boost callback(if HW support is needed). For software
> > > > > managed boost, special Kconfig flag - CONFIG_CPU_FREQ_BOOST_SW
> > > > > has been defined. It will be selected only when a target
> > > > > platform has thermal framework properly configured.
> > > > >
> > > > > - struct cpufreq_driver has been extended with boost related
> > > > > fields: -- boost_supported - when driver supports boosting
> > > > > -- boost_enabled - boost state
> > > > > -- set_boost - callback to function, which is necessary
> > > > > to enable/disable boost
> > > > >
> > > > > - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost)
> > > > > is visible _only_ when cpufreq driver supports Boost.
> > > > >
> > > > > - No special spin_lock for Boost was created. The one from
> > > > > cpufreq core was reused.
> > > > >
> > > > > - The Boost code doesn't rely on any policy. When boost state is
> > > > > changed, then the policy list is iterated and proper
> > > > > adjustements are done.
> > > > >
> > > > > - To improve safety level, the thermal framework is also
> > > > > extended to disable software boosting, when thermal trip point
> > > > > is reached. Then it starts monitoring target temperature to
> > > > > evaluate if boost can be enabled again. This emulates behaviour
> > > > > similar to HW managed boost (like x86)
> > > > >
> > > > > Tested at HW:
> > > > > Exynos 4412 3.11-rc4 Linux
> > > > > Intel Core i7-3770 3.11-rc4 Linux
> > > > >
> > > > > Above patches were posted on top of linux_pm/linux-next with
> > > > > following patches applied:
> > > > >
> > > > > cpufreq: exynos5440: Fix to skip when new frequency same as
> > > > > current cpufreq: fix EXYNOS drivers selection
> > > > >
> > > > > Lukasz Majewski (7):
> > > > > cpufreq: Add boost frequency support in core
> > > > > cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with
> > > > > common boost solution
> > > > > thermal:boost: Automatic enable/disable of BOOST feature
> > > > > cpufreq:boost:Kconfig: Provide support for software managed
> > > > > BOOST cpufreq:exynos:Extend Exynos cpufreq driver to support
> > > > > boost framework
> > > > > Documentation:cpufreq:boost: Update BOOST documentation
> > > > > cpufreq:exynos4x12: Change L0 driver data to
> > > > > CPUFREQ_BOOST_FREQ
> > > >
> > > > Hi Lukasz,
> > > >
> > >
> > > Hi Viresh,
> > >
> > > > I haven't found time yet to go through this series..
> > >
> > > I've just started wondering if I had send those patches
> > > correctly :-).
> > >
> > > > I want to do a
> > > > deep/careful review this time as these are almost the final
> > > > patches.
> > >
> > > Ok.
> > >
> > > >
> > > > Will try to get over them by the end of this week..
> > >
> > > Ok, I understand.
> >
> > Do I assume correctly that this stuff has been tested on
> > ACPI-compatible x86 with acpi-cpufreq and everything has worked
> > correctly there?
> >
> > Rafael
> >
>
> Hi Rafael,
>
> Following test configuration/test case (x86):
>
> - DELL OptiPlex 9010 Intel Core i7-3770
> - Linux repo: [kernel_pm_http/bleeding-edge] [kernel_pm_http/linux-next]
> SHA1: a238ea5e20be7bea2b1fc951a024ecce770306b5
> with v7 applied on top
>
> - Linux version: 3.11-rc4 (patches v7) and 3.11-rc1 (v6)
>
> - Ubuntu 11.10 (make bzImage + make all when module was needed)
> - config_ubuntu_3_11 (the default one for ubuntu)
> - KConfig:
> 1. Disabled intel_pstate driver
> 2. Enabled ACPI-Prosessor P state driver
> 3. Legacy cpb sysfs knob support for AMD CPUs ON/OFF (which is a
> part of acpi-cpufreq.c driver).
>
> - acpi-cpufreq driver was build as a module or was embedded in kernel
> (tested with modprobe -i / -r => no dmesg error|warning output)
>
> - I was able to read/write (echo 0/1
> > /sys/devices/system/cpu/cpufreq/boost) => no output at dmesg -
> system was working stable.
>
> Toolchain: gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
>
> Since I'm mostly working with ARM (exynos4412) and major work was done
> with cpufreq core (and x86 related work was to move common code to
> cpufreq core) tests mostly have been performed on ARM.
>
> Tests on ARM:
> - Stress tests with up to 4 scripts running to enable/disable boost
> sysfs attribute with random time interval (gzip < /dev/urandom
> > /dev/null).
> - Test to overheat the ARM target and look if boost+thermal cools down
> the device and enables boost again.
> - LAB governor (which was already posted to ML) to boost when power
> envelope allows it.
Great, thanks a lot for the info!
Rafael
Some minor nitpicking, nothing much :)
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> +static int cpufreq_boost_set_sw(int state)
> +{
> + struct cpufreq_frequency_table *freq_table;
> + struct cpufreq_policy *policy;
> + int ret = -EINVAL;
> +
> + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
> + freq_table = cpufreq_frequency_get_table(policy->cpu);
> + if (freq_table) {
> + ret = cpufreq_frequency_table_cpuinfo(policy,
> + freq_table);
> + if (!ret) {
> + policy->user_policy.max = policy->max;
> + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
> + }
In case ret wasn't 0 (i.e. we failed), we should print an error
message and break
our loop ?
> + }
> + }
> +
> + return ret;
> +}
> +
> +int cpufreq_boost_trigger_state(int state)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + if (cpufreq_driver->boost_enabled == state)
> + return 0;
> +
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + cpufreq_driver->boost_enabled = state;
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +
> + ret = cpufreq_driver->set_boost(state);
> + if (ret) {
> + write_lock_irqsave(&cpufreq_driver_lock, flags);
> + cpufreq_driver->boost_enabled = !state;
> + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +
> + pr_err("%s: Cannot %s BOOST\n", __func__,
> + state ? "enabled" : "disabled");
s/enabled/enable and s/disabled/disable
> + }
> +
> + return ret;
> +}
> +
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> The Intel's hardware based boost solution driver has been changed to cooperate with
> common cpufreq boost framework.
>
> The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
> has been moved to a core cpufreq code. This attribute is now only visible,
> when cpufreq driver supports it.
>
> The _store_boost() function has been redesigned to be used as set_boost
> callback.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v7:
> - Remove superfluous acpi_cpufreq_driver.boost_supported = false at
> acpi_cpufreq_boost_init()
Acked-by: Viresh Kumar <[email protected]>
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index b5defd4..ec19da9 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -408,10 +408,24 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
>
> void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
> ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
> +#ifdef CONFIG_CPU_FREQ
> int cpufreq_boost_trigger_state(int state);
> int cpufreq_boost_supported(void);
> int cpufreq_boost_enabled(void);
> -
> +#else
> +static inline int cpufreq_boost_trigger_state(int state)
> +{
> + return 0;
> +}
> +static inline int cpufreq_boost_supported(void)
> +{
> + return 0;
> +}
> +static inline int cpufreq_boost_enabled(void)
> +{
> + return 0;
> +}
> +#endif
I almost gave an Ack before I saw this :)
This should be moved to the first patch I believe..
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
> Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
> option the software managed boost is enabled. It also selects thermal
> subsystem to be compiled in. Thermal is necessary for disabling boost
> and cooling down the device when overheating detected.
>
> Boost _MUST_NOT_ work without thermal subsystem with properly defined
> overheating temperatures.
>
> This option doesn't affect x86's ACPI hardware managed boost support
> (i.e. Intel, AMD). In this situation boost management is embedded at
> hardware.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v7:
> - Remove superfluous "default n" definition
> - Generic CPU_FREQ_BOOST_SW depends on THERMAL
Acked-by: Viresh Kumar <[email protected]>
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> The cpufreq_driver's boost_supported flag is true only when boost
> support is explicitly enabled. Boost related attributes are exported only
> under the same condition.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v7:
> - Replace CONFIG_CPU_FREQ_BOOST_SW with CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
> - Move boost_supported initialization to struct cpufreq_driver exynos_driver
Acked-by: Viresh Kumar <[email protected]>
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> Since the support for software and hardware controlled boosting has been
> added, the corresponding Documentation entry had been updated.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v7:
> - None
Acked-by: Viresh Kumar <[email protected]>
On 13 August 2013 15:38, Lukasz Majewski <[email protected]> wrote:
> Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
> frequency, which can be only enabled for BOOST mode.
> This frequency shall be used only for limited time, since it might cause
> target device to overheat.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v7:
> - None
Acked-by: Viresh Kumar <[email protected]>
On Mon, 26 Aug 2013 11:03:51 +0530 Viresh Kumar [email protected]
wrote,
> On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> wrote:
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index b5defd4..ec19da9 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -408,10 +408,24 @@ int cpufreq_frequency_table_target(struct
> > cpufreq_policy *policy,
> >
> > void cpufreq_frequency_table_update_policy_cpu(struct
> > cpufreq_policy *policy); ssize_t cpufreq_show_cpus(const struct
> > cpumask *mask, char *buf); +#ifdef CONFIG_CPU_FREQ
> > int cpufreq_boost_trigger_state(int state);
> > int cpufreq_boost_supported(void);
> > int cpufreq_boost_enabled(void);
> > -
> > +#else
> > +static inline int cpufreq_boost_trigger_state(int state)
> > +{
> > + return 0;
> > +}
> > +static inline int cpufreq_boost_supported(void)
> > +{
> > + return 0;
> > +}
> > +static inline int cpufreq_boost_enabled(void)
> > +{
> > + return 0;
> > +}
> > +#endif
>
> I almost gave an Ack before I saw this :)
> This should be moved to the first patch I believe..
Ok, I will move it there.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar [email protected]
wrote,
> Some minor nitpicking, nothing much :)
Is there any chance to pull those corrected patches to v3.12?
>
> On 13 August 2013 15:38, Lukasz Majewski <[email protected]>
> wrote:
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > +static int cpufreq_boost_set_sw(int state)
> > +{
> > + struct cpufreq_frequency_table *freq_table;
> > + struct cpufreq_policy *policy;
> > + int ret = -EINVAL;
> > +
> > + list_for_each_entry(policy, &cpufreq_policy_list,
> > policy_list) {
> > + freq_table =
> > cpufreq_frequency_get_table(policy->cpu);
> > + if (freq_table) {
> > + ret =
> > cpufreq_frequency_table_cpuinfo(policy,
> > + freq_table);
> > + if (!ret) {
> > + policy->user_policy.max =
> > policy->max;
> > + __cpufreq_governor(policy,
> > CPUFREQ_GOV_LIMITS);
> > + }
>
> In case ret wasn't 0 (i.e. we failed), we should print an error
> message and break
> our loop ?
After your comments I think, that this code could be rewritten:
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
if (freq_table) {
ret = cpufreq_frequency_table_cpuinfo(policy,
freq_table);
if (ret) {
pr_err("%s: Policy frequency update
failed\n")
break;
}
policy->user_policy.max = policy->max;
__cpufreq_governor(policy,CPUFREQ_GOV_LIMITS);
}
}
return ret;
}
>
> > + }
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + if (cpufreq_driver->boost_enabled == state)
> > + return 0;
> > +
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + cpufreq_driver->boost_enabled = state;
> > + write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > +
> > + ret = cpufreq_driver->set_boost(state);
> > + if (ret) {
> > + write_lock_irqsave(&cpufreq_driver_lock, flags);
> > + cpufreq_driver->boost_enabled = !state;
> > + write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags); +
> > + pr_err("%s: Cannot %s BOOST\n", __func__,
> > + state ? "enabled" : "disabled");
>
> s/enabled/enable and s/disabled/disable
Ok.
>
> > + }
> > +
> > + return ret;
> > +}
> > +
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 26 August 2013 12:32, Lukasz Majewski <[email protected]> wrote:
> On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar [email protected]
> wrote,
>> Some minor nitpicking, nothing much :)
>
> Is there any chance to pull those corrected patches to v3.12?
Only Rafael can decide :)
> After your comments I think, that this code could be rewritten:
>
>
> list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
> freq_table = cpufreq_frequency_get_table(policy->cpu);
> if (freq_table) {
> ret = cpufreq_frequency_table_cpuinfo(policy,
> freq_table);
> if (ret) {
> pr_err("%s: Policy frequency update
> failed\n")
Don't break strings into multiple lines even if they cross 80 columns..
And you missed __func__ :)
> break;
> }
>
> policy->user_policy.max = policy->max;
> __cpufreq_governor(policy,CPUFREQ_GOV_LIMITS);
> }
> }
>
> return ret;
> }
On Mon, 26 Aug 2013 12:36:47 +0530 Viresh Kumar [email protected]
wrote,
> On 26 August 2013 12:32, Lukasz Majewski <[email protected]>
> wrote:
> > On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar
> > [email protected] wrote,
> >> Some minor nitpicking, nothing much :)
> >
> > Is there any chance to pull those corrected patches to v3.12?
>
> Only Rafael can decide :)
:-)
>
> > After your comments I think, that this code could be rewritten:
> >
> >
> > list_for_each_entry(policy, &cpufreq_policy_list,
> > policy_list) { freq_table =
> > cpufreq_frequency_get_table(policy->cpu); if (freq_table) {
> > ret =
> > cpufreq_frequency_table_cpuinfo(policy, freq_table);
> > if (ret) {
> > pr_err("%s: Policy frequency update
> > failed\n")
>
> Don't break strings into multiple lines even if they cross 80
> columns.. And you missed __func__ :)
C code which turned into the pseudo code :-).
>
> > break;
> > }
> >
> > policy->user_policy.max = policy->max;
> > __cpufreq_governor(policy,CPUFREQ_GOV_LIMITS);
> > }
> > }
> >
> > return ret;
> > }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On Monday, August 26, 2013 09:11:14 AM Lukasz Majewski wrote:
> On Mon, 26 Aug 2013 12:36:47 +0530 Viresh Kumar [email protected]
> wrote,
> > On 26 August 2013 12:32, Lukasz Majewski <[email protected]>
> > wrote:
> > > On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar
> > > [email protected] wrote,
> > >> Some minor nitpicking, nothing much :)
> > >
> > > Is there any chance to pull those corrected patches to v3.12?
> >
> > Only Rafael can decide :)
>
> :-)
Well, 3.11 is a week away and the 3.12 merge window will open then.
Honestly, I'd prefer this stuff to spend a couple of weeks in linux-next
before pushing it to Linus, so this means 3.13 I'm afraid.
Thanks,
Rafael
On 26 August 2013 18:42, Rafael J. Wysocki <[email protected]> wrote:
> On Monday, August 26, 2013 09:11:14 AM Lukasz Majewski wrote:
>> On Mon, 26 Aug 2013 12:36:47 +0530 Viresh Kumar [email protected]
>> wrote,
>> > On 26 August 2013 12:32, Lukasz Majewski <[email protected]>
>> > wrote:
>> > > On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar
>> > > [email protected] wrote,
>> > >> Some minor nitpicking, nothing much :)
>> > >
>> > > Is there any chance to pull those corrected patches to v3.12?
>> >
>> > Only Rafael can decide :)
>>
>> :-)
>
> Well, 3.11 is a week away and the 3.12 merge window will open then.
>
> Honestly, I'd prefer this stuff to spend a couple of weeks in linux-next
> before pushing it to Linus, so this means 3.13 I'm afraid.
+1
On Mon, 26 Aug 2013 19:30:07 +0530 Viresh Kumar [email protected]
wrote,
> On 26 August 2013 18:42, Rafael J. Wysocki <[email protected]> wrote:
> > On Monday, August 26, 2013 09:11:14 AM Lukasz Majewski wrote:
> >> On Mon, 26 Aug 2013 12:36:47 +0530 Viresh Kumar
> >> [email protected] wrote,
> >> > On 26 August 2013 12:32, Lukasz Majewski <[email protected]>
> >> > wrote:
> >> > > On Mon, 26 Aug 2013 10:58:53 +0530 Viresh Kumar
> >> > > [email protected] wrote,
> >> > >> Some minor nitpicking, nothing much :)
> >> > >
> >> > > Is there any chance to pull those corrected patches to v3.12?
> >> >
> >> > Only Rafael can decide :)
> >>
> >> :-)
> >
> > Well, 3.11 is a week away and the 3.12 merge window will open then.
> >
> > Honestly, I'd prefer this stuff to spend a couple of weeks in
> > linux-next before pushing it to Linus, so this means 3.13 I'm
> > afraid.
>
> +1
Ok. I understand.
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing set_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- boost_enabled - boost state
-- set_boost - callback to function, which is necessary to
enable/disable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
Tested at HW:
Exynos 4412 3.11-rc6 Linux
Intel Core i7-3770 3.11-rc6 Linux
Above patches were posted on top of linux_pm/linux-next
(SHA1: 68327ee544d74f20bb6179637971912e5e78811c)
Lukasz Majewski (7):
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Provide support for software managed BOOST
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
Documentation:cpufreq:boost: Update BOOST documentation
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Documentation/cpu-freq/boost.txt | 26 ++++----
drivers/cpufreq/Kconfig | 4 ++
drivers/cpufreq/Kconfig.arm | 15 +++++
drivers/cpufreq/acpi-cpufreq.c | 86 +++++++++----------------
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++-
drivers/cpufreq/exynos-cpufreq.c | 6 ++
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 53 +++++++++++++--
drivers/thermal/thermal_core.c | 55 ++++++++++++++++
include/linux/cpufreq.h | 25 +++++++
include/linux/thermal.h | 2 +
11 files changed, 313 insertions(+), 79 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency
above its normal operation limits. Such mode shall be only used for a
short time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) overclocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code. By default boost is disabled. One global
attribute is available at: /sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with a proper call
to sysfs.
The cpufreq_boost_trigger_state() function is defined non static on purpose.
It is used later with thermal subsystem to provide automatic enable/disable
of the BOOST feature.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v8:
- Correction of error message at cpufreq_boost_trigger_state() function
- Rewrite the cpufreq_boost_set_sw() function to print error message and
break the loop when policy adjustment fails
Changes for v7:
- Properly change cpufreq_driver->boost_enabled when set_boost() fails
(=0 to =!state)
- Add likely() around cpufreq_driver
- Remove parenthesis around boost.attr
Changes for v6:
- Remove sysfs boost attribute when subsys_iterface_unregister() fails
- Move global boost_enabled variable from cpufreq.c to platform dependent
struct cpufreq_driver
- pr_err() message is also printed when boost disable fails
- Call __cpufreq_governor() to force recalculation of next frequency when
boost is triggered. It is needed with i.e. performance class of governors
- Change cpufreq_boost_enable_sw() -> cpufreq_boost_set_sw()
- Rename .enable_boost function pointer to .set_boost
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++++++++++-
drivers/cpufreq/freq_table.c | 53 ++++++++++++++++---
include/linux/cpufreq.h | 25 +++++++++
3 files changed, 188 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5c75e31..b8b70a1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -344,6 +344,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %s BOOST!\n", __func__,
+ enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -2010,6 +2037,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_set_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (ret) {
+ pr_err("%s: Policy frequency update failed\n",
+ __func__);
+ break;
+ }
+ policy->user_policy.max = policy->max;
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (cpufreq_driver->boost_enabled == state)
+ return 0;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ ret = cpufreq_driver->set_boost(state);
+ if (ret) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = !state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_err("%s: Cannot %s BOOST\n", __func__,
+ state ? "enable" : "disable");
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (likely(cpufreq_driver))
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return cpufreq_driver->boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2048,9 +2142,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_boost_supported()) {
+ /*
+ * Check if driver provides function to enable boost -
+ * if not, use cpufreq_boost_set_sw as default
+ */
+ if (!cpufreq_driver->set_boost)
+ cpufreq_driver->set_boost = cpufreq_boost_set_sw;
+
+ ret = cpufreq_sysfs_create_file(&boost.attr);
+ if (ret) {
+ pr_err("%s: cannot register global BOOST sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
- goto err_null_driver;
+ goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
@@ -2077,6 +2187,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_boost_unreg:
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2103,6 +2216,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
down_write(&cpufreq_rwsem);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f111454a..d7eed63 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -169,7 +173,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ bool show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -184,6 +189,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq
+ * display BOOST freqs
+ *
+ * show_boost = false and driver_data = BOOST freq
+ * show_boost = true and driver_data != BOOST freq
+ * continue - do not display anything
+ *
+ * show_boost = false and driver_data != BOOST freq
+ * display NON BOOST freqs
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -192,14 +211,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, false);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, true);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d568f39..541d032 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -209,6 +209,11 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost) (int state);
};
/* flags */
@@ -381,6 +386,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+#define CPUFREQ_BOOST_FREQ ~2
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
@@ -403,11 +409,30 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
+#else
+static inline int cpufreq_boost_trigger_state(int state)
+{
+ return 0;
+}
+static inline int cpufreq_boost_supported(void)
+{
+ return 0;
+}
+static inline int cpufreq_boost_enabled(void)
+{
+ return 0;
+}
+#endif
/* the following funtion is for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
void cpufreq_frequency_table_put_attr(unsigned int cpu);
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Remove superfluous acpi_cpufreq_driver.boost_supported = false at
acpi_cpufreq_boost_init()
Changes for v6:
- Perform acpi_cpufreq_boost_init initialization before cpufreq_driver
registration
- Compile store_boost() only when CONFIG_X86_ACPI_CPUFREQ_CPB defined
- Use boost_enabled flag defined at acpi_cpufreq_driver to store information
about boost state
- Instead of using cpufreq_set_boost_enabled(), modify the boost_enable in
the acpi driver code
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 86 ++++++++++++++--------------------------
1 file changed, 29 insertions(+), 57 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index a1260b4..5ff169f 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
get_online_cpus();
-
boost_set_msrs(val, cpu_online_mask);
-
put_online_cpus();
-
- boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
-}
-
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
+ return 0;
}
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
+static ssize_t store_boost(const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val = 0;
+
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost((int) val);
+
+ return count;
+}
+
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
}
cpufreq_freq_attr_rw(cpb);
@@ -582,7 +565,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -937,6 +920,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.attr = acpi_cpufreq_attr,
+ .set_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -947,33 +931,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
-
+ acpi_cpufreq_driver.boost_supported = true;
+ acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
+ cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1015,12 +988,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb;
}
#endif
+ acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret)
free_acpi_perf_data();
- else
- acpi_cpufreq_boost_init();
return ret;
}
--
1.7.10.4
The cpufreq_driver's boost_supported flag is true only when boost
support is explicitly enabled. Boost related attributes are exported only
under the same condition.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Replace CONFIG_CPU_FREQ_BOOST_SW with CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
- Move boost_supported initialization to struct cpufreq_driver exynos_driver
Changes for v6:
- Replace exynos_driver.boost_supported = 1 to = true
- Protect boost attributes export with CONFIG_CPU_FREQ_BOOST_SW
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index b9f9aee..2786aba 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ &cpufreq_freq_attr_scaling_boost_freqs,
+#endif
NULL,
};
@@ -282,6 +285,9 @@ static struct cpufreq_driver exynos_driver = {
.exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
.attr = exynos_cpufreq_attr,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ .boost_supported = true,
+#endif
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v8:
- Move cpufreq_boost_* stub functions definition (needed when cpufreq
is not compiled in) to cpufreq.h at cpufreq core support commit
Changes for v7:
- None
Changes for v6:
- Disable boost only when supported and enabled
- Protect boost related thermal_zone_device struct fields with mutex
- Evaluate temperature trend during boost enable decision
- Create separate methods to handle boost enable/disable
(thermal_boost_{enable|disable}) operations
- Boost is disabled at any trip point passage (not only the non critical one)
- Add stub definitions for cpufreq boost functions used when
CONFIG_CPU_FREQ is NOT defined.
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 2 ++
2 files changed, 57 insertions(+)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1f02e8e..8f4be55 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -354,9 +355,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
}
+static int thermal_boost_enable(struct thermal_zone_device *tz)
+{
+ enum thermal_trend trend = get_tz_trend(tz, 0);
+ long trip_temp;
+
+ if (!tz->ops->get_trip_temp || !tz->overheated)
+ return -EPERM;
+ if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
+ return -EBUSY;
+
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ mutex_lock(&tz->lock);
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ }
+ mutex_unlock(&tz->lock);
+ cpufreq_boost_trigger_state(1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void thermal_boost_disable(struct thermal_zone_device *tz)
+{
+ cpufreq_boost_trigger_state(0);
+
+ /*
+ * If no workqueue for monitoring is running - start one with
+ * 1000 ms monitoring period
+ * If workqueue already running - do not change its period and only
+ * test if target CPU has cooled down
+ */
+ mutex_lock(&tz->lock);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ tz->overheated = true;
+ mutex_unlock(&tz->lock);
+}
+
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ if (cpufreq_boost_supported() && cpufreq_boost_enabled())
+ thermal_boost_disable(tz);
tz->ops->get_trip_type(tz, trip, &type);
@@ -455,6 +506,10 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ if (cpufreq_boost_supported())
+ if (!thermal_boost_enable(tz))
+ return;
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1c..f1aa3c2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- None
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
option the software managed boost is enabled. It also selects thermal
subsystem to be compiled in. Thermal is necessary for disabling boost
and cooling down the device when overheating detected.
Boost _MUST_NOT_ work without thermal subsystem with properly defined
overheating temperatures.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Remove superfluous "default n" definition
- Generic CPU_FREQ_BOOST_SW depends on THERMAL
Changes for v6:
- CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
- Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
added. It depends on ARM_EXYNOS_CPUFREQ options and selects
EXYNOS_THERMAL with the main boost config [1].
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 4 ++++
drivers/cpufreq/Kconfig.arm | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 534fcb8..e3cbf72 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,10 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool
+ depends on THERMAL
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0fa204b..6a6d173 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -67,6 +67,21 @@ config ARM_EXYNOS5440_CPUFREQ
If in doubt, say N.
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly
+ defined trip points.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
--
1.7.10.4
Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
frequency, which can be only enabled for BOOST mode.
This frequency shall be used only for limited time, since it might cause
target device to overheat.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- New patch
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index e270b42..367f600 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = {
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
--
1.7.10.4
On 26 August 2013 21:20, Lukasz Majewski <[email protected]> wrote:
> This patch series introduces support for CPU overclocking technique
> called Boost.
>
> It is a follow up of a LAB governor proposal. Boost is a LAB component:
> http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
>
> Boost unifies hardware based solution (e.g. Intel Nehalem) with
> software oriented one (like the one done at Exynos).
> For this reason cpufreq/freq_table code has been reorganized to include
> common code.
>
> Important design decisions:
> - Boost related code is compiled-in unconditionally to cpufreq core and
> disabled by default. The cpufreq_driver is responsibile for setting
> boost_supported flag and providing set_boost callback(if HW support
> is needed). For software managed boost, special Kconfig flag -
> CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
> when a target platform has thermal framework properly configured.
>
> - struct cpufreq_driver has been extended with boost related fields:
> -- boost_supported - when driver supports boosting
> -- boost_enabled - boost state
> -- set_boost - callback to function, which is necessary to
> enable/disable boost
>
> - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
> _only_ when cpufreq driver supports Boost.
>
> - No special spin_lock for Boost was created. The one from cpufreq core
> was reused.
>
> - The Boost code doesn't rely on any policy. When boost state is changed,
> then the policy list is iterated and proper adjustements are done.
>
> - To improve safety level, the thermal framework is also extended to disable
> software boosting, when thermal trip point is reached. Then it starts
> monitoring target temperature to evaluate if boost can be enabled
> again. This emulates behaviour similar to HW managed boost (like x86)
>
> Tested at HW:
> Exynos 4412 3.11-rc6 Linux
> Intel Core i7-3770 3.11-rc6 Linux
>
> Above patches were posted on top of linux_pm/linux-next
> (SHA1: 68327ee544d74f20bb6179637971912e5e78811c)
>
> Lukasz Majewski (7):
> cpufreq: Add boost frequency support in core
> cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
> boost solution
> thermal:boost: Automatic enable/disable of BOOST feature
> cpufreq:boost:Kconfig: Provide support for software managed BOOST
> cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> framework
> Documentation:cpufreq:boost: Update BOOST documentation
> cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
>
> Documentation/cpu-freq/boost.txt | 26 ++++----
> drivers/cpufreq/Kconfig | 4 ++
> drivers/cpufreq/Kconfig.arm | 15 +++++
> drivers/cpufreq/acpi-cpufreq.c | 86 +++++++++----------------
> drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++-
> drivers/cpufreq/exynos-cpufreq.c | 6 ++
> drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
> drivers/cpufreq/freq_table.c | 53 +++++++++++++--
> drivers/thermal/thermal_core.c | 55 ++++++++++++++++
> include/linux/cpufreq.h | 25 +++++++
> include/linux/thermal.h | 2 +
> 11 files changed, 313 insertions(+), 79 deletions(-)
Sorry for the long delays in getting this patchset in :)
Acked-by: Viresh Kumar <[email protected]>
On Tue, 27 Aug 2013 11:10:42 +0530 Viresh Kumar [email protected]
wrote,
> On 26 August 2013 21:20, Lukasz Majewski <[email protected]>
> wrote:
> > This patch series introduces support for CPU overclocking technique
> > called Boost.
> >
> > It is a follow up of a LAB governor proposal. Boost is a LAB
> > component:
> > http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
> >
> > Boost unifies hardware based solution (e.g. Intel Nehalem) with
> > software oriented one (like the one done at Exynos).
> > For this reason cpufreq/freq_table code has been reorganized to
> > include common code.
> >
> > Important design decisions:
> > - Boost related code is compiled-in unconditionally to cpufreq core
> > and disabled by default. The cpufreq_driver is responsibile for
> > setting boost_supported flag and providing set_boost callback(if HW
> > support is needed). For software managed boost, special Kconfig
> > flag - CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be
> > selected only when a target platform has thermal framework properly
> > configured.
> >
> > - struct cpufreq_driver has been extended with boost related fields:
> > -- boost_supported - when driver supports boosting
> > -- boost_enabled - boost state
> > -- set_boost - callback to function, which is necessary to
> > enable/disable boost
> >
> > - Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is
> > visible _only_ when cpufreq driver supports Boost.
> >
> > - No special spin_lock for Boost was created. The one from cpufreq
> > core was reused.
> >
> > - The Boost code doesn't rely on any policy. When boost state is
> > changed, then the policy list is iterated and proper adjustements
> > are done.
> >
> > - To improve safety level, the thermal framework is also extended
> > to disable software boosting, when thermal trip point is reached.
> > Then it starts monitoring target temperature to evaluate if boost
> > can be enabled again. This emulates behaviour similar to HW managed
> > boost (like x86)
> >
> > Tested at HW:
> > Exynos 4412 3.11-rc6 Linux
> > Intel Core i7-3770 3.11-rc6 Linux
> >
> > Above patches were posted on top of linux_pm/linux-next
> > (SHA1: 68327ee544d74f20bb6179637971912e5e78811c)
> >
> > Lukasz Majewski (7):
> > cpufreq: Add boost frequency support in core
> > cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with
> > common boost solution
> > thermal:boost: Automatic enable/disable of BOOST feature
> > cpufreq:boost:Kconfig: Provide support for software managed BOOST
> > cpufreq:exynos:Extend Exynos cpufreq driver to support boost
> > framework
> > Documentation:cpufreq:boost: Update BOOST documentation
> > cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
> >
> > Documentation/cpu-freq/boost.txt | 26 ++++----
> > drivers/cpufreq/Kconfig | 4 ++
> > drivers/cpufreq/Kconfig.arm | 15 +++++
> > drivers/cpufreq/acpi-cpufreq.c | 86
> > +++++++++---------------- drivers/cpufreq/cpufreq.c |
> > 118 +++++++++++++++++++++++++++++++++-
> > drivers/cpufreq/exynos-cpufreq.c | 6 ++
> > drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
> > drivers/cpufreq/freq_table.c | 53 +++++++++++++--
> > drivers/thermal/thermal_core.c | 55 ++++++++++++++++
> > include/linux/cpufreq.h | 25 +++++++
> > include/linux/thermal.h | 2 + 11 files changed, 313
> > insertions(+), 79 deletions(-)
>
> Sorry for the long delays in getting this patchset in :)
>
> Acked-by: Viresh Kumar <[email protected]>
Thanks Viresh :-).
For my future work it is important, to "stabilize" those patches at
some kernel_pm branch (linux-next or other).
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
On 27 August 2013 14:15, Lukasz Majewski <[email protected]> wrote:
> For my future work it is important, to "stabilize" those patches at
> some kernel_pm branch (linux-next or other).
You can rebase them over 3.12-rc1 as soon as it is released after few
weeks and then Rafael can get them into linux-next.
That is some important piece of information that might be useful for
others and so cc'ing LKML and other lists..
On 11 September 2013 01:06, Rafael J. Wysocki <[email protected]> wrote:
> On Tuesday, September 10, 2013 02:16:03 PM Lukasz Majewski wrote:
>> For my curiosity - what is the difference between bleeding-edge and
>> linux-next branches at kernel_pm?
>
> linux-next are patches that I'm going to push to Linus in the future and that
> have passed automated build testing. I still may drop one of them occasionally
> or add tags to commits and rebase the branch as a result, though.
>
> bleeding-edge is linux-next plus patches under automated build testing, but it
> may contain some purely experimental stuff too. During a merge window, like
> for example today, it also may contain material for the second next release
> (like 3.13 at the moment).
>
> In addition to those, there are topic branches like pm-cpufreq, acpica etc.
> that are only material either in the Linus' tree already or going to be pushed
> to Linus going forward and I don't rebase them.
>
> So if you want a stable branch to work on top of, either use one of the topic
> branches (but please note that they may be somewhat behind Linus sometimes), or
> ask me for one directly.
>
> Thanks,
> Rafael
>
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing set_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- boost_enabled - boost state
-- set_boost - callback to function, which is necessary to
enable/disable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
Tested at HW:
Exynos 4412 (TRATS2) 3.12-rc1 Linux
Intel Core i7-3770 3.12-rc1 Linux
Above patches were posted on top of linux_pm/linux-next
SHA1: cf8bc6460f2137412081ba26d18932f20cb856fd
Lukasz Majewski (7):
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Provide support for software managed BOOST
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
Documentation:cpufreq:boost: Update BOOST documentation
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Documentation/cpu-freq/boost.txt | 26 ++++----
drivers/cpufreq/Kconfig | 4 ++
drivers/cpufreq/Kconfig.arm | 15 +++++
drivers/cpufreq/acpi-cpufreq.c | 86 +++++++++----------------
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++-
drivers/cpufreq/exynos-cpufreq.c | 6 ++
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 53 +++++++++++++--
drivers/thermal/thermal_core.c | 55 ++++++++++++++++
include/linux/cpufreq.h | 25 +++++++
include/linux/thermal.h | 2 +
11 files changed, 313 insertions(+), 79 deletions(-)
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency
above its normal operation limits. Such mode shall be only used for a
short time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) overclocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code. By default boost is disabled. One global
attribute is available at: /sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with a proper call
to sysfs.
The cpufreq_boost_trigger_state() function is defined non static on purpose.
It is used later with thermal subsystem to provide automatic enable/disable
of the BOOST feature.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- Correction of error message at cpufreq_boost_trigger_state() function
- Rewrite the cpufreq_boost_set_sw() function to print error message and
break the loop when policy adjustment fails
Changes for v7:
- Properly change cpufreq_driver->boost_enabled when set_boost() fails
(=0 to =!state)
- Add likely() around cpufreq_driver
- Remove parenthesis around boost.attr
Changes for v6:
- Remove sysfs boost attribute when subsys_iterface_unregister() fails
- Move global boost_enabled variable from cpufreq.c to platform dependent
struct cpufreq_driver
- pr_err() message is also printed when boost disable fails
- Call __cpufreq_governor() to force recalculation of next frequency when
boost is triggered. It is needed with i.e. performance class of governors
- Change cpufreq_boost_enable_sw() -> cpufreq_boost_set_sw()
- Rename .enable_boost function pointer to .set_boost
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++++++++++-
drivers/cpufreq/freq_table.c | 53 ++++++++++++++++---
include/linux/cpufreq.h | 25 +++++++++
3 files changed, 188 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5c75e31..b8b70a1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -344,6 +344,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %s BOOST!\n", __func__,
+ enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -2010,6 +2037,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_set_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (ret) {
+ pr_err("%s: Policy frequency update failed\n",
+ __func__);
+ break;
+ }
+ policy->user_policy.max = policy->max;
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (cpufreq_driver->boost_enabled == state)
+ return 0;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ ret = cpufreq_driver->set_boost(state);
+ if (ret) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = !state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_err("%s: Cannot %s BOOST\n", __func__,
+ state ? "enable" : "disable");
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (likely(cpufreq_driver))
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return cpufreq_driver->boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2048,9 +2142,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_boost_supported()) {
+ /*
+ * Check if driver provides function to enable boost -
+ * if not, use cpufreq_boost_set_sw as default
+ */
+ if (!cpufreq_driver->set_boost)
+ cpufreq_driver->set_boost = cpufreq_boost_set_sw;
+
+ ret = cpufreq_sysfs_create_file(&boost.attr);
+ if (ret) {
+ pr_err("%s: cannot register global BOOST sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
- goto err_null_driver;
+ goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
@@ -2077,6 +2187,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_boost_unreg:
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2103,6 +2216,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
down_write(&cpufreq_rwsem);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f111454a..d7eed63 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -169,7 +173,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ bool show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -184,6 +189,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq
+ * display BOOST freqs
+ *
+ * show_boost = false and driver_data = BOOST freq
+ * show_boost = true and driver_data != BOOST freq
+ * continue - do not display anything
+ *
+ * show_boost = false and driver_data != BOOST freq
+ * display NON BOOST freqs
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -192,14 +211,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, false);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, true);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
/*
* if you use these, you must assure that the frequency table is valid
* all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d568f39..541d032 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -209,6 +209,11 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost) (int state);
};
/* flags */
@@ -381,6 +386,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+#define CPUFREQ_BOOST_FREQ ~2
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
@@ -403,11 +409,30 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
+#else
+static inline int cpufreq_boost_trigger_state(int state)
+{
+ return 0;
+}
+static inline int cpufreq_boost_supported(void)
+{
+ return 0;
+}
+static inline int cpufreq_boost_enabled(void)
+{
+ return 0;
+}
+#endif
/* the following funtion is for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu);
void cpufreq_frequency_table_put_attr(unsigned int cpu);
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Remove superfluous acpi_cpufreq_driver.boost_supported = false at
acpi_cpufreq_boost_init()
Changes for v6:
- Perform acpi_cpufreq_boost_init initialization before cpufreq_driver
registration
- Compile store_boost() only when CONFIG_X86_ACPI_CPUFREQ_CPB defined
- Use boost_enabled flag defined at acpi_cpufreq_driver to store information
about boost state
- Instead of using cpufreq_set_boost_enabled(), modify the boost_enable in
the acpi driver code
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 86 ++++++++++++++--------------------------
1 file changed, 29 insertions(+), 57 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index a1260b4..5ff169f 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
get_online_cpus();
-
boost_set_msrs(val, cpu_online_mask);
-
put_online_cpus();
-
- boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
-}
-
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
+ return 0;
}
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
+static ssize_t store_boost(const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val = 0;
+
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost((int) val);
+
+ return count;
+}
+
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
}
cpufreq_freq_attr_rw(cpb);
@@ -582,7 +565,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -937,6 +920,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.attr = acpi_cpufreq_attr,
+ .set_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -947,33 +931,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
-
+ acpi_cpufreq_driver.boost_supported = true;
+ acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
+ cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1015,12 +988,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb;
}
#endif
+ acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret)
free_acpi_perf_data();
- else
- acpi_cpufreq_boost_init();
return ret;
}
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
option the software managed boost is enabled. It also selects thermal
subsystem to be compiled in. Thermal is necessary for disabling boost
and cooling down the device when overheating detected.
Boost _MUST_NOT_ work without thermal subsystem with properly defined
overheating temperatures.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Remove superfluous "default n" definition
- Generic CPU_FREQ_BOOST_SW depends on THERMAL
Changes for v6:
- CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
- Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
added. It depends on ARM_EXYNOS_CPUFREQ options and selects
EXYNOS_THERMAL with the main boost config [1].
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 4 ++++
drivers/cpufreq/Kconfig.arm | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 534fcb8..e3cbf72 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -23,6 +23,10 @@ config CPU_FREQ_TABLE
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool
+ depends on THERMAL
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0fa204b..6a6d173 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -67,6 +67,21 @@ config ARM_EXYNOS5440_CPUFREQ
If in doubt, say N.
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly
+ defined trip points.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
--
1.7.10.4
The cpufreq_driver's boost_supported flag is true only when boost
support is explicitly enabled. Boost related attributes are exported only
under the same condition.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- Replace CONFIG_CPU_FREQ_BOOST_SW with CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
- Move boost_supported initialization to struct cpufreq_driver exynos_driver
Changes for v6:
- Replace exynos_driver.boost_supported = 1 to = true
- Protect boost attributes export with CONFIG_CPU_FREQ_BOOST_SW
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index b9f9aee..2786aba 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -270,6 +270,9 @@ static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static struct freq_attr *exynos_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ &cpufreq_freq_attr_scaling_boost_freqs,
+#endif
NULL,
};
@@ -282,6 +285,9 @@ static struct cpufreq_driver exynos_driver = {
.exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
.attr = exynos_cpufreq_attr,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ .boost_supported = true,
+#endif
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
--
1.7.10.4
Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
frequency, which can be only enabled for BOOST mode.
This frequency shall be used only for limited time, since it might cause
target device to overheat.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- New patch
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index e270b42..367f600 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = {
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- None
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v8:
- Move cpufreq_boost_* stub functions definition (needed when cpufreq
is not compiled in) to cpufreq.h at cpufreq core support commit
Changes for v7:
- None
Changes for v6:
- Disable boost only when supported and enabled
- Protect boost related thermal_zone_device struct fields with mutex
- Evaluate temperature trend during boost enable decision
- Create separate methods to handle boost enable/disable
(thermal_boost_{enable|disable}) operations
- Boost is disabled at any trip point passage (not only the non critical one)
- Add stub definitions for cpufreq boost functions used when
CONFIG_CPU_FREQ is NOT defined.
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 2 ++
2 files changed, 57 insertions(+)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1f02e8e..8f4be55 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -354,9 +355,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
}
+static int thermal_boost_enable(struct thermal_zone_device *tz)
+{
+ enum thermal_trend trend = get_tz_trend(tz, 0);
+ long trip_temp;
+
+ if (!tz->ops->get_trip_temp || !tz->overheated)
+ return -EPERM;
+ if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
+ return -EBUSY;
+
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ mutex_lock(&tz->lock);
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ }
+ mutex_unlock(&tz->lock);
+ cpufreq_boost_trigger_state(1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void thermal_boost_disable(struct thermal_zone_device *tz)
+{
+ cpufreq_boost_trigger_state(0);
+
+ /*
+ * If no workqueue for monitoring is running - start one with
+ * 1000 ms monitoring period
+ * If workqueue already running - do not change its period and only
+ * test if target CPU has cooled down
+ */
+ mutex_lock(&tz->lock);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ tz->overheated = true;
+ mutex_unlock(&tz->lock);
+}
+
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ if (cpufreq_boost_supported() && cpufreq_boost_enabled())
+ thermal_boost_disable(tz);
tz->ops->get_trip_type(tz, trip, &type);
@@ -455,6 +506,10 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ if (cpufreq_boost_supported())
+ if (!thermal_boost_enable(tz))
+ return;
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a386a1c..f1aa3c2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
This patch series introduces support for CPU overclocking technique
called Boost.
It is a follow up of a LAB governor proposal. Boost is a LAB component:
http://thread.gmane.org/gmane.linux.kernel/1484746/match=cpufreq
Boost unifies hardware based solution (e.g. Intel Nehalem) with
software oriented one (like the one done at Exynos).
For this reason cpufreq/freq_table code has been reorganized to include
common code.
Important design decisions:
- Boost related code is compiled-in unconditionally to cpufreq core and
disabled by default. The cpufreq_driver is responsibile for setting
boost_supported flag and providing set_boost callback(if HW support
is needed). For software managed boost, special Kconfig flag -
CONFIG_CPU_FREQ_BOOST_SW has been defined. It will be selected only
when a target platform has thermal framework properly configured.
- struct cpufreq_driver has been extended with boost related fields:
-- boost_supported - when driver supports boosting
-- boost_enabled - boost state
-- set_boost - callback to function, which is necessary to
enable/disable boost
- Boost sysfs attribute (/sys/devices/system/cpu/cpufreq/boost) is visible
_only_ when cpufreq driver supports Boost.
- No special spin_lock for Boost was created. The one from cpufreq core
was reused.
- The Boost code doesn't rely on any policy. When boost state is changed,
then the policy list is iterated and proper adjustements are done.
- To improve safety level, the thermal framework is also extended to disable
software boosting, when thermal trip point is reached. Then it starts
monitoring target temperature to evaluate if boost can be enabled
again. This emulates behaviour similar to HW managed boost (like x86)
Tested at HW:
Exynos 4412 3.12-rc4 Linux
Intel Core i7-3770 3.12-rc4 Linux
Above patches were posted on top of kernel_pm/bleeding-edge
(SHA1: d06a5fe3485062acdb5552dffe3a89672e1a439d)
Lukasz Majewski (7):
cpufreq: Add boost frequency support in core
cpufreq:acpi:x86: Adjust the acpi-cpufreq.c code to work with common
boost solution
thermal:boost: Automatic enable/disable of BOOST feature
cpufreq:boost:Kconfig: Provide support for software managed BOOST
cpufreq:exynos:Extend Exynos cpufreq driver to support boost
framework
Documentation:cpufreq:boost: Update BOOST documentation
cpufreq:exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
Documentation/cpu-freq/boost.txt | 26 ++++----
drivers/cpufreq/Kconfig | 4 ++
drivers/cpufreq/Kconfig.arm | 15 +++++
drivers/cpufreq/acpi-cpufreq.c | 86 +++++++++----------------
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++-
drivers/cpufreq/exynos-cpufreq.c | 3 +
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
drivers/cpufreq/freq_table.c | 56 ++++++++++++++--
drivers/thermal/thermal_core.c | 55 ++++++++++++++++
include/linux/cpufreq.h | 24 +++++++
include/linux/thermal.h | 2 +
11 files changed, 312 insertions(+), 79 deletions(-)
--
1.7.10.4
The Intel's hardware based boost solution driver has been changed to cooperate with
common cpufreq boost framework.
The global sysfs boost attribute entry code (/sys/devices/system/cpu/cpufreq/boost)
has been moved to a core cpufreq code. This attribute is now only visible,
when cpufreq driver supports it.
The _store_boost() function has been redesigned to be used as set_boost
callback.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v9:
- None
Changes for v8:
- None
Changes for v7:
- Remove superfluous acpi_cpufreq_driver.boost_supported = false at
acpi_cpufreq_boost_init()
Changes for v6:
- Perform acpi_cpufreq_boost_init initialization before cpufreq_driver
registration
- Compile store_boost() only when CONFIG_X86_ACPI_CPUFREQ_CPB defined
- Use boost_enabled flag defined at acpi_cpufreq_driver to store information
about boost state
- Instead of using cpufreq_set_boost_enabled(), modify the boost_enable in
the acpi driver code
Changes for v5:
- Remove acpi-cpufreq's boost_enabled global flag and reuse one defined at
cpufreq core
Changes for v4:
- add _store_boost to acpi_cpufreq_driver structure
Changes for v3:
- Bring back boost_enabled as a global flag
- Move boost_supported to cpufreq_driver structure
Changes for v2:
- Replace boost_enabled and boost_supported global flags with proper entries
at struct cpufreq_driver.
- Removal of struct cpufreq_boost
drivers/cpufreq/acpi-cpufreq.c | 86 ++++++++++++++--------------------------
1 file changed, 29 insertions(+), 57 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index a8dac7b..6a92530 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu)
@@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs);
}
-static ssize_t _store_boost(const char *buf, size_t count)
+static int _store_boost(int val)
{
- int ret;
- unsigned long val = 0;
-
- if (!boost_supported)
- return -EINVAL;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret || (val > 1))
- return -EINVAL;
-
- if ((val && boost_enabled) || (!val && !boost_enabled))
- return count;
-
get_online_cpus();
-
boost_set_msrs(val, cpu_online_mask);
-
put_online_cpus();
-
- boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
- return count;
-}
-
-static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- return _store_boost(buf, count);
-}
-
-static ssize_t show_global_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", boost_enabled);
+ return 0;
}
-static struct global_attr global_boost = __ATTR(boost, 0644,
- show_global_boost,
- store_global_boost);
-
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
+static ssize_t store_boost(const char *buf, size_t count)
+{
+ int ret;
+ unsigned long val = 0;
+
+ if (!acpi_cpufreq_driver.boost_supported)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret || (val > 1))
+ return -EINVAL;
+
+ _store_boost((int) val);
+
+ return count;
+}
+
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
{
- return _store_boost(buf, count);
+ return store_boost(buf, count);
}
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", boost_enabled);
+ return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
}
cpufreq_freq_attr_rw(cpb);
@@ -573,7 +556,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- boost_set_msrs(boost_enabled, cpumask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break;
case CPU_DOWN_PREPARE:
@@ -925,6 +908,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.attr = acpi_cpufreq_attr,
+ .set_boost = _store_boost,
};
static void __init acpi_cpufreq_boost_init(void)
@@ -935,33 +919,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs)
return;
- boost_supported = true;
- boost_enabled = boost_state(0);
-
+ acpi_cpufreq_driver.boost_supported = true;
+ acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus();
/* Force all MSRs to the same value */
- boost_set_msrs(boost_enabled, cpu_online_mask);
+ boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
+ cpu_online_mask);
register_cpu_notifier(&boost_nb);
put_online_cpus();
- } else
- global_boost.attr.mode = 0444;
-
- /* We create the boost file in any case, though for systems without
- * hardware support it will be read-only and hardwired to return 0.
- */
- if (cpufreq_sysfs_create_file(&(global_boost.attr)))
- pr_warn(PFX "could not register global boost sysfs file\n");
- else
- pr_debug("registered global boost sysfs file\n");
+ }
}
static void __exit acpi_cpufreq_boost_exit(void)
{
- cpufreq_sysfs_remove_file(&(global_boost.attr));
-
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1007,12 +980,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb;
}
#endif
+ acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret)
free_acpi_perf_data();
- else
- acpi_cpufreq_boost_init();
return ret;
}
--
1.7.10.4
For safety reasons new flag - CONFIG_CPU_FREQ_BOOST_SW has been added.
Only after selecting "EXYNOS Frequency Overclocking - Software" Kconfig
option the software managed boost is enabled. It also selects thermal
subsystem to be compiled in. Thermal is necessary for disabling boost
and cooling down the device when overheating detected.
Boost _MUST_NOT_ work without thermal subsystem with properly defined
overheating temperatures.
This option doesn't affect x86's ACPI hardware managed boost support
(i.e. Intel, AMD). In this situation boost management is embedded at
hardware.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v9:
- None
Changes for v8:
- None
Changes for v7:
- Remove superfluous "default n" definition
- Generic CPU_FREQ_BOOST_SW depends on THERMAL
Changes for v6:
- CPU_FREQ_BOOST_SW [1] is now defined as "invisible" bool option.
- Platform dependent ARM_EXYNOS_CPU_FREQ_BOOST_SW config option has been
added. It depends on ARM_EXYNOS_CPUFREQ options and selects
EXYNOS_THERMAL with the main boost config [1].
Changes for v5:
- New patch
drivers/cpufreq/Kconfig | 4 ++++
drivers/cpufreq/Kconfig.arm | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 38093e2..c8818c1 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -20,6 +20,10 @@ if CPU_FREQ
config CPU_FREQ_GOV_COMMON
bool
+config CPU_FREQ_BOOST_SW
+ bool
+ depends on THERMAL
+
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
default y
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 701ec95..549166a 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -64,6 +64,21 @@ config ARM_EXYNOS5440_CPUFREQ
If in doubt, say N.
+config ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ bool "EXYNOS Frequency Overclocking - Software"
+ depends on ARM_EXYNOS_CPUFREQ
+ select CPU_FREQ_BOOST_SW
+ select EXYNOS_THERMAL
+ help
+ This driver supports software managed overclocking (BOOST).
+ It allows usage of special frequencies for Samsung Exynos
+ processors if thermal conditions are appropriate.
+
+ It reguires, for safe operation, thermal framework with properly
+ defined trip points.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
--
1.7.10.4
Special driver data flag (CPUFREQ_BOOST_FREQ) has been added to indicate
frequency, which can be only enabled for BOOST mode.
This frequency shall be used only for limited time, since it might cause
target device to overheat.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v9:
- None
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- New patch
drivers/cpufreq/exynos4x12-cpufreq.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index 08b7477..178ab4b 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = {
};
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, CPUFREQ_ENTRY_INVALID},
+ {CPUFREQ_BOOST_FREQ, 1500 * 1000},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
--
1.7.10.4
This patch provides auto disable/enable operation for boost. When any
defined trip point is passed, the boost is disabled.
In that moment thermal monitor workqueue is woken up and it monitors
if the device temperature drops below 75% of the smallest trip point.
When device cools down, the boost is enabled again.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v9:
- None
Changes for v8:
- Move cpufreq_boost_* stub functions definition (needed when cpufreq
is not compiled in) to cpufreq.h at cpufreq core support commit
Changes for v7:
- None
Changes for v6:
- Disable boost only when supported and enabled
- Protect boost related thermal_zone_device struct fields with mutex
- Evaluate temperature trend during boost enable decision
- Create separate methods to handle boost enable/disable
(thermal_boost_{enable|disable}) operations
- Boost is disabled at any trip point passage (not only the non critical one)
- Add stub definitions for cpufreq boost functions used when
CONFIG_CPU_FREQ is NOT defined.
Changes for v5:
- Move boost disable code from cpu_cooling.c to thermal_core.c
(to handle_non_critical_trips)
- Extent struct thermal_zone_device by adding overheated bool flag
- Implement auto enable of boost after device cools down
- Introduce boost_polling flag, which indicates if thermal uses it's predefined
pool delay or has woken up thermal workqueue only to wait until device
cools down.
Changes for v4:
- New patch
drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 2 ++
2 files changed, 57 insertions(+)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 4962a6a..a167ab9 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
+#include <linux/cpufreq.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -366,9 +367,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
}
+static int thermal_boost_enable(struct thermal_zone_device *tz)
+{
+ enum thermal_trend trend = get_tz_trend(tz, 0);
+ long trip_temp;
+
+ if (!tz->ops->get_trip_temp || !tz->overheated)
+ return -EPERM;
+ if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
+ return -EBUSY;
+
+ tz->ops->get_trip_temp(tz, 0, &trip_temp);
+ /*
+ * Enable boost again only when current temperature is less
+ * than 75% of trip_temp[0]
+ */
+ if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
+ mutex_lock(&tz->lock);
+ tz->overheated = false;
+ if (tz->boost_polling) {
+ tz->boost_polling = false;
+ tz->polling_delay = 0;
+ }
+ mutex_unlock(&tz->lock);
+ cpufreq_boost_trigger_state(1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void thermal_boost_disable(struct thermal_zone_device *tz)
+{
+ cpufreq_boost_trigger_state(0);
+
+ /*
+ * If no workqueue for monitoring is running - start one with
+ * 1000 ms monitoring period
+ * If workqueue already running - do not change its period and only
+ * test if target CPU has cooled down
+ */
+ mutex_lock(&tz->lock);
+ if (!tz->polling_delay) {
+ tz->boost_polling = true;
+ tz->polling_delay = 1000;
+ }
+ tz->overheated = true;
+ mutex_unlock(&tz->lock);
+}
+
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ if (cpufreq_boost_supported() && cpufreq_boost_enabled())
+ thermal_boost_disable(tz);
tz->ops->get_trip_type(tz, trip, &type);
@@ -467,6 +518,10 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
+ if (cpufreq_boost_supported())
+ if (!thermal_boost_enable(tz))
+ return;
+
thermal_zone_device_update(tz);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index b268d3c..b316bdf 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -172,6 +172,8 @@ struct thermal_zone_device {
int emul_temperature;
int passive;
unsigned int forced_passive;
+ bool overheated;
+ bool boost_polling;
const struct thermal_zone_device_ops *ops;
const struct thermal_zone_params *tzp;
struct thermal_governor *governor;
--
1.7.10.4
Since the support for software and hardware controlled boosting has been
added, the corresponding Documentation entry had been updated.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v9:
- None
Changes for v8:
- None
Changes for v7:
- None
Changes for v6:
- None
Changes for v5:
- New patch
Documentation/cpu-freq/boost.txt | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/cpu-freq/boost.txt b/Documentation/cpu-freq/boost.txt
index 9b4edfc..dd62e13 100644
--- a/Documentation/cpu-freq/boost.txt
+++ b/Documentation/cpu-freq/boost.txt
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal
-budget. This is done without operating system control by a combination
-of hardware and firmware.
+budget. The decision about boost disable/enable is made either at hardware
+(e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch
----------------------
-To allow the user to toggle the boosting functionality, the acpi-cpufreq
-driver exports a sysfs knob to disable it. There is a file:
+To allow the user to toggle the boosting functionality, the cpufreq core
+driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled).
-Reading the file is always supported, even if the processor does not
-support boosting. In this case the file will be read-only and always
-reads as "0". Explicitly changing the permissions and writing to that
-file anyway will return EINVAL.
+The file is exported only when cpufreq driver supports boosting.
+Explicitly changing the permissions and writing to that file anyway will
+return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the
-whole system (0) or will allow the hardware to boost at will (1).
+whole system (0) or will allow the software or hardware to boost at will
+(1).
Writing a "1" does not explicitly boost the system, but just allows the
-CPU (and the firmware) to boost at their discretion. Some implementations
-take external factors like the chip's temperature into account, so
-boosting once does not necessarily mean that it will occur every time
-even using the exact same software setup.
+CPU to boost at their discretion. Some implementations take external
+factors like the chip's temperature into account, so boosting once does
+not necessarily mean that it will occur every time even using the exact
+same software setup.
AMD legacy cpb switch
--
1.7.10.4
This commit adds boost frequency support in cpufreq core (Hardware &
Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency
above its normal operation limits. Such mode shall be only used for a
short time.
Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.
This commit unifies support for SW and HW (Intel) overclocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code. By default boost is disabled. One global
attribute is available at: /sys/devices/system/cpu/cpufreq/boost.
It only shows up when cpufreq driver supports overclocking.
Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with a proper call
to sysfs.
The cpufreq_boost_trigger_state() function is defined non static on purpose.
It is used later with thermal subsystem to provide automatic enable/disable
of the BOOST feature.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
---
Changes for v9:
- Add cpufreq_freq_attr_scaling_boost_freqs to *cpufreq_generic_attr table
- Introduce CONFIG_CPU_FREQ_BOOST_SW generic config flag to show BOOST
frequencies only when cpufreq driver supports boost
Changes for v8:
- Correction of error message at cpufreq_boost_trigger_state() function
- Rewrite the cpufreq_boost_set_sw() function to print error message and
break the loop when policy adjustment fails
Changes for v7:
- Properly change cpufreq_driver->boost_enabled when set_boost() fails
(=0 to =!state)
- Add likely() around cpufreq_driver
- Remove parenthesis around boost.attr
Changes for v6:
- Remove sysfs boost attribute when subsys_iterface_unregister() fails
- Move global boost_enabled variable from cpufreq.c to platform dependent
struct cpufreq_driver
- pr_err() message is also printed when boost disable fails
- Call __cpufreq_governor() to force recalculation of next frequency when
boost is triggered. It is needed with i.e. performance class of governors
- Change cpufreq_boost_enable_sw() -> cpufreq_boost_set_sw()
- Rename .enable_boost function pointer to .set_boost
Changes for v5:
- Rename cpufreq_boost_trigger_state_sw() to cpufreq_boost_enable_sw()
- Extent cpufreq_register_driver() to check if cpufreq driver provided
boost_enable callback. If not provided, then use cpufreq_boost_enable_sw()
- Use single call to cpufreq_driver->enable_boost() with cpufreq driver
provided callback or default SW boost enable routine
- Move pr_debug call to store_boost() from cpufreq_boost_trigger_state()
- Change the user_policy.max value when SW boost is toggled. It is necessary
for proper operation of e.g. thermal subsystem.
- Add check if cpufreq_driver pointer is not NULL at
cpufreq_boost_supported() routine
- Add EXPORT_SYMBOL_GPL for cpufreq_boost_supported() and
cpufreq_boost_enabled()
- Remove extra check for cpufreq_boost_supported() at
cpufreq_freq_table_cpuinfo()
- Explanation of show boost logic at show_available_freqs()
- Add cpufreq_set_boost_enabled() method to set initial value of boost_enabled
global flag
Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
at SW.
- Protect boost_enabled manipulation with lock.
Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines
Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
drivers/cpufreq/cpufreq.c | 118 +++++++++++++++++++++++++++++++++++++++++-
drivers/cpufreq/freq_table.c | 56 +++++++++++++++++---
include/linux/cpufreq.h | 24 +++++++++
3 files changed, 190 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8a3914b..9be28eb 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -319,6 +319,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+
+ ret = sscanf(buf, "%d", &enable);
+ if (ret != 1 || enable < 0 || enable > 1)
+ return -EINVAL;
+
+ if (cpufreq_boost_trigger_state(enable)) {
+ pr_err("%s: Cannot %s BOOST!\n", __func__,
+ enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: cpufreq BOOST %s\n", __func__,
+ enable ? "enabled" : "disabled");
+
+ return count;
+}
+define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor)
{
@@ -2038,6 +2065,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
};
/*********************************************************************
+ * BOOST *
+ *********************************************************************/
+static int cpufreq_boost_set_sw(int state)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct cpufreq_policy *policy;
+ int ret = -EINVAL;
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ freq_table = cpufreq_frequency_get_table(policy->cpu);
+ if (freq_table) {
+ ret = cpufreq_frequency_table_cpuinfo(policy,
+ freq_table);
+ if (ret) {
+ pr_err("%s: Policy frequency update failed\n",
+ __func__);
+ break;
+ }
+ policy->user_policy.max = policy->max;
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_trigger_state(int state)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (cpufreq_driver->boost_enabled == state)
+ return 0;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ ret = cpufreq_driver->set_boost(state);
+ if (ret) {
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ cpufreq_driver->boost_enabled = !state;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ pr_err("%s: Cannot %s BOOST\n", __func__,
+ state ? "enable" : "disable");
+ }
+
+ return ret;
+}
+
+int cpufreq_boost_supported(void)
+{
+ if (likely(cpufreq_driver))
+ return cpufreq_driver->boost_supported;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
+
+int cpufreq_boost_enabled(void)
+{
+ return cpufreq_driver->boost_enabled;
+}
+EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
+
+/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -2076,9 +2170,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (cpufreq_boost_supported()) {
+ /*
+ * Check if driver provides function to enable boost -
+ * if not, use cpufreq_boost_set_sw as default
+ */
+ if (!cpufreq_driver->set_boost)
+ cpufreq_driver->set_boost = cpufreq_boost_set_sw;
+
+ ret = cpufreq_sysfs_create_file(&boost.attr);
+ if (ret) {
+ pr_err("%s: cannot register global BOOST sysfs file\n",
+ __func__);
+ goto err_null_driver;
+ }
+ }
+
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
- goto err_null_driver;
+ goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
@@ -2105,6 +2215,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
+err_boost_unreg:
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
@@ -2131,6 +2244,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface);
+ if (cpufreq_boost_supported())
+ cpufreq_sysfs_remove_file(&boost.attr);
+
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
down_write(&cpufreq_rwsem);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 3458d27..776e88a 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
+ if (!cpufreq_boost_enabled()
+ && table[i].driver_data == CPUFREQ_BOOST_FREQ)
+ continue;
+
pr_debug("table entry %u: %u kHz, %u driver_data\n",
i, freq, table[i].driver_data);
if (freq < min_freq)
@@ -182,7 +186,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+ bool show_boost)
{
unsigned int i = 0;
unsigned int cpu = policy->cpu;
@@ -197,6 +202,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
+ /*
+ * show_boost = true and driver_data = BOOST freq
+ * display BOOST freqs
+ *
+ * show_boost = false and driver_data = BOOST freq
+ * show_boost = true and driver_data != BOOST freq
+ * continue - do not display anything
+ *
+ * show_boost = false and driver_data != BOOST freq
+ * display NON BOOST freqs
+ */
+ if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
+ continue;
+
count += sprintf(&buf[count], "%d ", table[i].frequency);
}
count += sprintf(&buf[count], "\n");
@@ -205,16 +224,39 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
}
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies",
- .mode = 0444,
- },
- .show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name) \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show available normal frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, false);
+}
+cpufreq_attr_available_freq(scaling_available);
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+ char *buf)
+{
+ return show_available_freqs(policy, buf, true);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
struct freq_attr *cpufreq_generic_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+#ifdef CONFIG_CPU_FREQ_BOOST_SW
+ &cpufreq_freq_attr_scaling_boost_freqs,
+#endif
NULL,
};
EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 6b457d0..0e3ca20 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -215,6 +215,11 @@ struct cpufreq_driver {
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
+
+ /* platform specific boost support code */
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost) (int state);
};
/* flags */
@@ -403,6 +408,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
+#define CPUFREQ_BOOST_FREQ ~2
struct cpufreq_frequency_table {
unsigned int driver_data; /* driver specific data, not used by core */
@@ -426,6 +432,24 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
+#else
+static inline int cpufreq_boost_trigger_state(int state)
+{
+ return 0;
+}
+static inline int cpufreq_boost_supported(void)
+{
+ return 0;
+}
+static inline int cpufreq_boost_enabled(void)
+{
+ return 0;
+}
+#endif
/* the following funtion is for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
--
1.7.10.4
The cpufreq_driver's boost_supported flag is true only when boost
support is explicitly enabled.
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Myungjoo Ham <[email protected]>
Acked-by: Viresh Kumar <[email protected]>
---
Changes for v9:
- The exynos_cpufreq_attr[] has been replaced by generic_cpufreq_attr[],
therefore the cpufreq_freq_attr_scaling_boost_freqs is now added at
freq_table.c file.
Changes for v8:
- None
Changes for v7:
- Replace CONFIG_CPU_FREQ_BOOST_SW with CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
- Move boost_supported initialization to struct cpufreq_driver exynos_driver
Changes for v6:
- Replace exynos_driver.boost_supported = 1 to = true
- Protect boost attributes export with CONFIG_CPU_FREQ_BOOST_SW
Changes for v5:
- None
Changes for v4:
- None
Changes for v3:
- Remove low level boost code
- Move boost management code to cpufreq core code
- Use boost_supported flag to indicate if driver supports over clocking
Changes for v2:
- Removal of struct cpufreq_boost
- Removal of the CONFIG_CPU_FREQ_BOOST flag
- low_level_boost with valid address when boost is supported
drivers/cpufreq/exynos-cpufreq.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index b96fcc8..77a0aed 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -253,6 +253,9 @@ static struct cpufreq_driver exynos_driver = {
.exit = cpufreq_generic_exit,
.name = "exynos_cpufreq",
.attr = cpufreq_generic_attr,
+#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
+ .boost_supported = true,
+#endif
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
--
1.7.10.4
Hi, Lukasz,
thanks for the patch, sorry that I didn't look into this one earlier.
On Mon, 2013-10-14 at 14:17 +0200, Lukasz Majewski wrote:
> This patch provides auto disable/enable operation for boost. When any
> defined trip point is passed, the boost is disabled.
Do you mean boost is disabled if the system is in a overheating state?
> In that moment thermal monitor workqueue is woken up and it monitors
> if the device temperature drops below 75% of the smallest trip point.
Just FYI, the smallest trip point does not equal the trip point with
lowest temperature value.
Say, here is a platform with an active trip point at 40C, and an
critical trip point at 100C, you want to enable boost only if the
temperature is under 30C, right?
> When device cools down, the boost is enabled again.
>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Myungjoo Ham <[email protected]>
>
> ---
> Changes for v9:
> - None
>
> Changes for v8:
> - Move cpufreq_boost_* stub functions definition (needed when cpufreq
> is not compiled in) to cpufreq.h at cpufreq core support commit
>
> Changes for v7:
> - None
>
> Changes for v6:
> - Disable boost only when supported and enabled
> - Protect boost related thermal_zone_device struct fields with mutex
> - Evaluate temperature trend during boost enable decision
> - Create separate methods to handle boost enable/disable
> (thermal_boost_{enable|disable}) operations
> - Boost is disabled at any trip point passage (not only the non critical one)
> - Add stub definitions for cpufreq boost functions used when
> CONFIG_CPU_FREQ is NOT defined.
>
> Changes for v5:
> - Move boost disable code from cpu_cooling.c to thermal_core.c
> (to handle_non_critical_trips)
> - Extent struct thermal_zone_device by adding overheated bool flag
> - Implement auto enable of boost after device cools down
> - Introduce boost_polling flag, which indicates if thermal uses it's predefined
> pool delay or has woken up thermal workqueue only to wait until device
> cools down.
>
> Changes for v4:
> - New patch
>
> drivers/thermal/thermal_core.c | 55 ++++++++++++++++++++++++++++++++++++++++
> include/linux/thermal.h | 2 ++
> 2 files changed, 57 insertions(+)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 4962a6a..a167ab9 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -34,6 +34,7 @@
> #include <linux/thermal.h>
> #include <linux/reboot.h>
> #include <linux/string.h>
> +#include <linux/cpufreq.h>
Actually, I do not like to see this as thermal_core.c.
Because it is the platform thermal driver that owns the thermal policy,
e.g. it tells the thermal core to take what action at what temperature.
And this cpufreq boost support should be part of the thermal policy.
For example, here is a platform that supports boost. And it has a
passive trip point at 40C, which means the platform driver wants to
reduce the processor frequency when the temperature at 40C.
And what you're trying to add in this patch is to turn on boost mode
when the temperature is under 30C, right?
If yes, then I'd prefer to
1. introduce a separate cpu cooling device that just has two cooling
state, 0 means boost mode enabled, and 1 means boost mode disabled.
2. For any platform thermal driver that wants this support, introduce a
new trip point (30C) to the platform thermal driver, and bind the
cpufreq boost cooling device to this trip point.
And IMO, Step 1 can be an enhancement of cpufreq cooling feature. You
just need to introduce two new APIs for registering/unregistering an cpu
boost cooling device, without changing the current cpufreq cooling code.
Further more, cpufreq_boost_trigger_state(1) just make it possible to
enter boost mode, it does not mean the cpu will be put into boost mode
immediately, right? can we make it transparent to thermal core, say,
always enable it when the cpu is in cooling state 0 (p0)?
thanks,
rui
> #include <net/netlink.h>
> #include <net/genetlink.h>
>
> @@ -366,9 +367,59 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
> }
> }
>
> +static int thermal_boost_enable(struct thermal_zone_device *tz)
> +{
> + enum thermal_trend trend = get_tz_trend(tz, 0);
> + long trip_temp;
> +
> + if (!tz->ops->get_trip_temp || !tz->overheated)
> + return -EPERM;
> + if (trend == THERMAL_TREND_RAISING || trend == THERMAL_TREND_RAISE_FULL)
> + return -EBUSY;
> +
> + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> + /*
> + * Enable boost again only when current temperature is less
> + * than 75% of trip_temp[0]
> + */
> + if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
> + mutex_lock(&tz->lock);
> + tz->overheated = false;
> + if (tz->boost_polling) {
> + tz->boost_polling = false;
> + tz->polling_delay = 0;
> + }
> + mutex_unlock(&tz->lock);
> + cpufreq_boost_trigger_state(1);
> + return 0;
> + }
> + return -EBUSY;
> +}
> +
> +static void thermal_boost_disable(struct thermal_zone_device *tz)
> +{
> + cpufreq_boost_trigger_state(0);
> +
> + /*
> + * If no workqueue for monitoring is running - start one with
> + * 1000 ms monitoring period
> + * If workqueue already running - do not change its period and only
> + * test if target CPU has cooled down
> + */
> + mutex_lock(&tz->lock);
> + if (!tz->polling_delay) {
> + tz->boost_polling = true;
> + tz->polling_delay = 1000;
> + }
> + tz->overheated = true;
> + mutex_unlock(&tz->lock);
> +}
> +
> static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> {
> enum thermal_trip_type type;
> + if (cpufreq_boost_supported() && cpufreq_boost_enabled())
> + thermal_boost_disable(tz);
>
> tz->ops->get_trip_type(tz, trip, &type);
>
> @@ -467,6 +518,10 @@ static void thermal_zone_device_check(struct work_struct *work)
> struct thermal_zone_device *tz = container_of(work, struct
> thermal_zone_device,
> poll_queue.work);
> + if (cpufreq_boost_supported())
> + if (!thermal_boost_enable(tz))
> + return;
> +
> thermal_zone_device_update(tz);
> }
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index b268d3c..b316bdf 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -172,6 +172,8 @@ struct thermal_zone_device {
> int emul_temperature;
> int passive;
> unsigned int forced_passive;
> + bool overheated;
> + bool boost_polling;
> const struct thermal_zone_device_ops *ops;
> const struct thermal_zone_params *tzp;
> struct thermal_governor *governor;
Hi Zhang,
> Hi, Lukasz,
>
> thanks for the patch, sorry that I didn't look into this one earlier.
Yes, I would _really_ appreciate _earlier_ feedback from thermal
maintainers :-)
>
> On Mon, 2013-10-14 at 14:17 +0200, Lukasz Majewski wrote:
> > This patch provides auto disable/enable operation for boost. When
> > any defined trip point is passed, the boost is disabled.
>
> Do you mean boost is disabled if the system is in a overheating state?
In short - Yes.
To be more precise - the thermal here is a "safe" valve.
Its role is to provide hysteresis similar to the one available for
Intel processors.
Intel does it in HW. Here I'm trying to do the same with SW for ARM.
>
> > In that moment thermal monitor workqueue is woken up and it monitors
> > if the device temperature drops below 75% of the smallest trip
> > point.
>
> Just FYI, the smallest trip point does not equal the trip point with
> lowest temperature value.
Thermal processors to which I've looked (exynos 4/5, ste-snowball) had
trip points defined monotonically with smallest value defined first.
This was the rationale for choosing thermal trip point 0.
>
> Say, here is a platform with an active trip point at 40C, and an
> critical trip point at 100C, you want to enable boost only if the
> temperature is under 30C, right?
In short: no (please read below explanation).
The boost rough idea:
1. I enable boost from cpufreq (no matter what is the state of thermal)
2. If temperature is too high, then thermal interrupt would trigger and
disable boost
3. If device cools down - I enable the boost again
>
> > When device cools down, the boost is enabled again.
> >
> > Signed-off-by: Lukasz Majewski <[email protected]>
> > Signed-off-by: Myungjoo Ham <[email protected]>
> >
> > ---
> > Changes for v9:
> > - None
> >
> > Changes for v8:
> > - Move cpufreq_boost_* stub functions definition (needed when
> > cpufreq is not compiled in) to cpufreq.h at cpufreq core support
> > commit
> >
> > Changes for v7:
> > - None
> >
> > Changes for v6:
> > - Disable boost only when supported and enabled
> > - Protect boost related thermal_zone_device struct fields with mutex
> > - Evaluate temperature trend during boost enable decision
> > - Create separate methods to handle boost enable/disable
> > (thermal_boost_{enable|disable}) operations
> > - Boost is disabled at any trip point passage (not only the non
> > critical one)
> > - Add stub definitions for cpufreq boost functions used when
> > CONFIG_CPU_FREQ is NOT defined.
> >
> > Changes for v5:
> > - Move boost disable code from cpu_cooling.c to thermal_core.c
> > (to handle_non_critical_trips)
> > - Extent struct thermal_zone_device by adding overheated bool flag
> > - Implement auto enable of boost after device cools down
> > - Introduce boost_polling flag, which indicates if thermal uses
> > it's predefined pool delay or has woken up thermal workqueue only
> > to wait until device cools down.
> >
> > Changes for v4:
> > - New patch
> >
> > drivers/thermal/thermal_core.c | 55
> > ++++++++++++++++++++++++++++++++++++++++
> > include/linux/thermal.h | 2 ++ 2 files changed, 57
> > insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c index 4962a6a..a167ab9 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -34,6 +34,7 @@
> > #include <linux/thermal.h>
> > #include <linux/reboot.h>
> > #include <linux/string.h>
> > +#include <linux/cpufreq.h>
>
> Actually, I do not like to see this as thermal_core.c.
> Because it is the platform thermal driver that owns the thermal
> policy, e.g. it tells the thermal core to take what action at what
> temperature.
> And this cpufreq boost support should be part of the
> thermal policy.
Boost is defined as policy independent at cpufreq. So I believe that
it shall be also thermal policy independent. In the end thermal shall
help cpufreq to not burn the device.
>
> For example, here is a platform that supports boost. And it has a
> passive trip point at 40C, which means the platform driver wants to
> reduce the processor frequency when the temperature at 40C.
> And what you're trying to add in this patch is to turn on boost mode
> when the temperature is under 30C, right?
In short: yes.
I want to add code which would disable boost when detected temperature
is more than 40C.
First, boost must be enabled at cpufreq. Only then it can be disabled
(if temp > 40C) at thermal.
During boost disablement I also setup the thermal zone for
polling (if we already poll it - no settings are changed).
The boost is re-enabled only when temperature drops to 30C AND the
tz->overheated is set (which means that we are at overheated state
caused by boost).
> If yes, then I'd prefer to
> 1. introduce a separate cpu cooling device that just has two cooling
> state, 0 means boost mode enabled, and 1 means boost mode disabled.
> 2. For any platform thermal driver that wants this support, introduce
> a new trip point (30C) to the platform thermal driver,
> and bind the
> cpufreq boost cooling device to this trip point.
>
> And IMO, Step 1 can be an enhancement of cpufreq cooling feature. You
> just need to introduce two new APIs for registering/unregistering an
> cpu boost cooling device, without changing the current cpufreq
> cooling code.
>
> Further more, cpufreq_boost_trigger_state(1) just make it possible to
> enter boost mode, it does not mean the cpu will be put into boost mode
> immediately, right?
Yes, correct.
> can we make it transparent to thermal core, say,
> always enable it when the cpu is in cooling state 0 (p0)?
Thanks for presenting possible solution.
I will investigate it for boost.
>
> thanks,
> rui
> > #include <net/netlink.h>
> > #include <net/genetlink.h>
> >
> > @@ -366,9 +367,59 @@ static void handle_critical_trips(struct
> > thermal_zone_device *tz, }
> > }
> >
> > +static int thermal_boost_enable(struct thermal_zone_device *tz)
> > +{
> > + enum thermal_trend trend = get_tz_trend(tz, 0);
> > + long trip_temp;
> > +
> > + if (!tz->ops->get_trip_temp || !tz->overheated)
> > + return -EPERM;
> > + if (trend == THERMAL_TREND_RAISING || trend ==
> > THERMAL_TREND_RAISE_FULL)
> > + return -EBUSY;
> > +
> > + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> > + /*
> > + * Enable boost again only when current temperature is less
> > + * than 75% of trip_temp[0]
> > + */
> > + if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
> > + mutex_lock(&tz->lock);
> > + tz->overheated = false;
> > + if (tz->boost_polling) {
> > + tz->boost_polling = false;
> > + tz->polling_delay = 0;
> > + }
> > + mutex_unlock(&tz->lock);
> > + cpufreq_boost_trigger_state(1);
> > + return 0;
> > + }
> > + return -EBUSY;
> > +}
> > +
> > +static void thermal_boost_disable(struct thermal_zone_device *tz)
> > +{
> > + cpufreq_boost_trigger_state(0);
> > +
> > + /*
> > + * If no workqueue for monitoring is running - start one
> > with
> > + * 1000 ms monitoring period
> > + * If workqueue already running - do not change its period
> > and only
> > + * test if target CPU has cooled down
> > + */
> > + mutex_lock(&tz->lock);
> > + if (!tz->polling_delay) {
> > + tz->boost_polling = true;
> > + tz->polling_delay = 1000;
> > + }
> > + tz->overheated = true;
> > + mutex_unlock(&tz->lock);
> > +}
> > +
> > static void handle_thermal_trip(struct thermal_zone_device *tz,
> > int trip) {
> > enum thermal_trip_type type;
> > + if (cpufreq_boost_supported() && cpufreq_boost_enabled())
> > + thermal_boost_disable(tz);
> >
> > tz->ops->get_trip_type(tz, trip, &type);
> >
> > @@ -467,6 +518,10 @@ static void thermal_zone_device_check(struct
> > work_struct *work) struct thermal_zone_device *tz =
> > container_of(work, struct thermal_zone_device,
> > poll_queue.work);
> > + if (cpufreq_boost_supported())
> > + if (!thermal_boost_enable(tz))
> > + return;
> > +
> > thermal_zone_device_update(tz);
> > }
> >
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index b268d3c..b316bdf 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -172,6 +172,8 @@ struct thermal_zone_device {
> > int emul_temperature;
> > int passive;
> > unsigned int forced_passive;
> > + bool overheated;
> > + bool boost_polling;
> > const struct thermal_zone_device_ops *ops;
> > const struct thermal_zone_params *tzp;
> > struct thermal_governor *governor;
>
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> -----Original Message-----
> From: Lukasz Majewski [mailto:[email protected]]
> Sent: Tuesday, October 15, 2013 11:43 PM
> To: Zhang, Rui
> Cc: Viresh Kumar; Rafael J. Wysocki; Eduardo Valentin;
> [email protected]; Linux PM list; Jonghwa Lee; Lukasz Majewski;
> linux-kernel; Bartlomiej Zolnierkiewicz; Myungjoo Ham; R, Durgadoss
> Subject: Re: [PATCH v9 3/7] thermal:boost: Automatic enable/disable of
> BOOST feature
> Importance: High
>
> Hi Zhang,
>
> > Hi, Lukasz,
> >
> > thanks for the patch, sorry that I didn't look into this one earlier.
>
> Yes, I would _really_ appreciate _earlier_ feedback from thermal
> maintainers :-)
>
> >
> > On Mon, 2013-10-14 at 14:17 +0200, Lukasz Majewski wrote:
> > > This patch provides auto disable/enable operation for boost. When
> > > any defined trip point is passed, the boost is disabled.
> >
> > Do you mean boost is disabled if the system is in a overheating state?
>
> In short - Yes.
>
>
> To be more precise - the thermal here is a "safe" valve.
>
> Its role is to provide hysteresis similar to the one available for
> Intel processors.
>
> Intel does it in HW. Here I'm trying to do the same with SW for ARM.
>
> >
> > > In that moment thermal monitor workqueue is woken up and it
> monitors
> > > if the device temperature drops below 75% of the smallest trip
> > > point.
> >
> > Just FYI, the smallest trip point does not equal the trip point with
> > lowest temperature value.
>
> Thermal processors to which I've looked (exynos 4/5, ste-snowball) had
> trip points defined monotonically with smallest value defined first.
>
> This was the rationale for choosing thermal trip point 0.
>
But this is not a hard rule for all thermal drivers, thus you can't make this assumption.
>
> >
> > Say, here is a platform with an active trip point at 40C, and an
> > critical trip point at 100C, you want to enable boost only if the
> > temperature is under 30C, right?
>
> In short: no (please read below explanation).
>
>
> The boost rough idea:
> 1. I enable boost from cpufreq (no matter what is the state of thermal)
> 2. If temperature is too high, then thermal interrupt would trigger and
> disable boost 3. If device cools down - I enable the boost again
>
>
> >
> > > When device cools down, the boost is enabled again.
> > >
> > > Signed-off-by: Lukasz Majewski <[email protected]>
> > > Signed-off-by: Myungjoo Ham <[email protected]>
> > >
> > > ---
> > > Changes for v9:
> > > - None
> > >
> > > Changes for v8:
> > > - Move cpufreq_boost_* stub functions definition (needed when
> > > cpufreq is not compiled in) to cpufreq.h at cpufreq core support
> > > commit
> > >
> > > Changes for v7:
> > > - None
> > >
> > > Changes for v6:
> > > - Disable boost only when supported and enabled
> > > - Protect boost related thermal_zone_device struct fields with
> mutex
> > > - Evaluate temperature trend during boost enable decision
> > > - Create separate methods to handle boost enable/disable
> > > (thermal_boost_{enable|disable}) operations
> > > - Boost is disabled at any trip point passage (not only the non
> > > critical one)
> > > - Add stub definitions for cpufreq boost functions used when
> > > CONFIG_CPU_FREQ is NOT defined.
> > >
> > > Changes for v5:
> > > - Move boost disable code from cpu_cooling.c to thermal_core.c
> > > (to handle_non_critical_trips)
> > > - Extent struct thermal_zone_device by adding overheated bool flag
> > > - Implement auto enable of boost after device cools down
> > > - Introduce boost_polling flag, which indicates if thermal uses
> it's
> > > predefined pool delay or has woken up thermal workqueue only to
> wait
> > > until device cools down.
> > >
> > > Changes for v4:
> > > - New patch
> > >
> > > drivers/thermal/thermal_core.c | 55
> > > ++++++++++++++++++++++++++++++++++++++++
> > > include/linux/thermal.h | 2 ++ 2 files changed, 57
> > > insertions(+)
> > >
> > > diff --git a/drivers/thermal/thermal_core.c
> > > b/drivers/thermal/thermal_core.c index 4962a6a..a167ab9 100644
> > > --- a/drivers/thermal/thermal_core.c
> > > +++ b/drivers/thermal/thermal_core.c
> > > @@ -34,6 +34,7 @@
> > > #include <linux/thermal.h>
> > > #include <linux/reboot.h>
> > > #include <linux/string.h>
> > > +#include <linux/cpufreq.h>
> >
> > Actually, I do not like to see this as thermal_core.c.
> > Because it is the platform thermal driver that owns the thermal
> > policy, e.g. it tells the thermal core to take what action at what
> > temperature.
> > And this cpufreq boost support should be part of the thermal policy.
>
>
> Boost is defined as policy independent at cpufreq.
> So I believe that
> it shall be also thermal policy independent.
Boost mode support itself is policy independent, but when to use it is kind of a policy, right?
Say, if you introduce boost support in cpufreq cooling code, either as a cooling device or as a special cooling state, it is thermal policy independent, but when to use this cooling device/state is surely part of thermal policy.
> In the end thermal shall
> help cpufreq to not burn the device.
>
>
> >
> > For example, here is a platform that supports boost. And it has a
> > passive trip point at 40C, which means the platform driver wants to
> > reduce the processor frequency when the temperature at 40C.
> > And what you're trying to add in this patch is to turn on boost mode
> > when the temperature is under 30C, right?
>
> In short: yes.
>
> I want to add code which would disable boost when detected temperature
> is more than 40C.
>
> First, boost must be enabled at cpufreq. Only then it can be disabled
> (if temp > 40C) at thermal.
>
> During boost disablement I also setup the thermal zone for
> polling (if we already poll it - no settings are changed).
>
> The boost is re-enabled only when temperature drops to 30C AND the
> tz->overheated is set (which means that we are at overheated state
> caused by boost).
>
>
> > If yes, then I'd prefer to
> > 1. introduce a separate cpu cooling device that just has two cooling
> > state, 0 means boost mode enabled, and 1 means boost mode disabled.
> > 2. For any platform thermal driver that wants this support, introduce
> > a new trip point (30C) to the platform thermal driver,
> > and bind the
> > cpufreq boost cooling device to this trip point.
>
> >
> > And IMO, Step 1 can be an enhancement of cpufreq cooling feature. You
> > just need to introduce two new APIs for registering/unregistering an
> > cpu boost cooling device, without changing the current cpufreq
> > cooling code.
> >
> > Further more, cpufreq_boost_trigger_state(1) just make it possible to
> > enter boost mode, it does not mean the cpu will be put into boost
> mode
> > immediately, right?
>
> Yes, correct.
>
> > can we make it transparent to thermal core, say,
> > always enable it when the cpu is in cooling state 0 (p0)?
>
> Thanks for presenting possible solution.
>
No problem.
Thanks,
rui
> I will investigate it for boost.
>
Thanks,
rui
> >
> > thanks,
> > rui
> > > #include <net/netlink.h>
> > > #include <net/genetlink.h>
> > >
> > > @@ -366,9 +367,59 @@ static void handle_critical_trips(struct
> > > thermal_zone_device *tz, }
> > > }
> > >
> > > +static int thermal_boost_enable(struct thermal_zone_device *tz)
> > > +{
> > > + enum thermal_trend trend = get_tz_trend(tz, 0);
> > > + long trip_temp;
> > > +
> > > + if (!tz->ops->get_trip_temp || !tz->overheated)
> > > + return -EPERM;
> > > + if (trend == THERMAL_TREND_RAISING || trend ==
> > > THERMAL_TREND_RAISE_FULL)
> > > + return -EBUSY;
> > > +
> > > + tz->ops->get_trip_temp(tz, 0, &trip_temp);
> > > + /*
> > > + * Enable boost again only when current temperature is less
> > > + * than 75% of trip_temp[0]
> > > + */
> > > + if ((tz->temperature + (trip_temp >> 2)) < trip_temp) {
> > > + mutex_lock(&tz->lock);
> > > + tz->overheated = false;
> > > + if (tz->boost_polling) {
> > > + tz->boost_polling = false;
> > > + tz->polling_delay = 0;
> > > + }
> > > + mutex_unlock(&tz->lock);
> > > + cpufreq_boost_trigger_state(1);
> > > + return 0;
> > > + }
> > > + return -EBUSY;
> > > +}
> > > +
> > > +static void thermal_boost_disable(struct thermal_zone_device *tz)
> > > +{
> > > + cpufreq_boost_trigger_state(0);
> > > +
> > > + /*
> > > + * If no workqueue for monitoring is running - start one
> > > with
> > > + * 1000 ms monitoring period
> > > + * If workqueue already running - do not change its period
> > > and only
> > > + * test if target CPU has cooled down
> > > + */
> > > + mutex_lock(&tz->lock);
> > > + if (!tz->polling_delay) {
> > > + tz->boost_polling = true;
> > > + tz->polling_delay = 1000;
> > > + }
> > > + tz->overheated = true;
> > > + mutex_unlock(&tz->lock);
> > > +}
> > > +
> > > static void handle_thermal_trip(struct thermal_zone_device *tz,
> > > int trip) {
> > > enum thermal_trip_type type;
> > > + if (cpufreq_boost_supported() && cpufreq_boost_enabled())
> > > + thermal_boost_disable(tz);
> > >
> > > tz->ops->get_trip_type(tz, trip, &type);
> > >
> > > @@ -467,6 +518,10 @@ static void thermal_zone_device_check(struct
> > > work_struct *work) struct thermal_zone_device *tz =
> > > container_of(work, struct thermal_zone_device,
> > > poll_queue.work);
> > > + if (cpufreq_boost_supported())
> > > + if (!thermal_boost_enable(tz))
> > > + return;
> > > +
> > > thermal_zone_device_update(tz);
> > > }
> > >
> > > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > > index b268d3c..b316bdf 100644
> > > --- a/include/linux/thermal.h
> > > +++ b/include/linux/thermal.h
> > > @@ -172,6 +172,8 @@ struct thermal_zone_device {
> > > int emul_temperature;
> > > int passive;
> > > unsigned int forced_passive;
> > > + bool overheated;
> > > + bool boost_polling;
> > > const struct thermal_zone_device_ops *ops;
> > > const struct thermal_zone_params *tzp;
> > > struct thermal_governor *governor;
> >
> >
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group