You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'pm-cpufreq'
* pm-cpufreq: (28 commits) cpufreq: handle calls to ->target_index() in separate routine cpufreq: s5pv210: drop check for CONFIG_PM_VERBOSE cpufreq: intel_pstate: Remove unused member name of cpudata cpufreq: Break out early when frequency equals target_freq cpufreq: Tegra: drop wrapper around tegra_update_cpu_speed() cpufreq: imx6q: Remove unused include cpufreq: imx6q: Drop devm_clk/regulator_get usage cpufreq: powernow-k8: Suppress checkpatch warnings cpufreq: powernv: make local function static cpufreq: Enable big.LITTLE cpufreq driver on arm64 cpufreq: nforce2: remove DEFINE_PCI_DEVICE_TABLE macro intel_pstate: Add CPU IDs for Broadwell processors cpufreq: Fix build error on some platforms that use cpufreq_for_each_* PM / OPP: Move cpufreq specific OPP functions out of generic OPP library PM / OPP: Remove cpufreq wrapper dependency on internal data organization cpufreq: Catch double invocations of cpufreq_freq_transition_begin/end intel_pstate: Remove sample parameter in intel_pstate_calc_busy cpufreq: Kconfig: Fix spelling errors cpufreq: Make linux-pm@vger.kernel.org official mailing list cpufreq: exynos: Use dev_err/info function instead of pr_err/info ...
This commit is contained in:
@@ -128,7 +128,7 @@ Description: Discover cpuidle policy and mechanism
|
||||
|
||||
What: /sys/devices/system/cpu/cpu#/cpufreq/*
|
||||
Date: pre-git history
|
||||
Contact: cpufreq@vger.kernel.org
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
Description: Discover and change clock speed of CPUs
|
||||
|
||||
Clock scaling allows you to change the clock speed of the
|
||||
@@ -146,7 +146,7 @@ Description: Discover and change clock speed of CPUs
|
||||
|
||||
What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
|
||||
Date: June 2013
|
||||
Contact: cpufreq@vger.kernel.org
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
Description: Discover CPUs in the same CPU frequency coordination domain
|
||||
|
||||
freqdomain_cpus is the list of CPUs (online+offline) that share
|
||||
|
||||
@@ -20,6 +20,7 @@ Contents:
|
||||
---------
|
||||
1. CPUFreq core and interfaces
|
||||
2. CPUFreq notifiers
|
||||
3. CPUFreq Table Generation with Operating Performance Point (OPP)
|
||||
|
||||
1. General Information
|
||||
=======================
|
||||
@@ -92,3 +93,31 @@ values:
|
||||
cpu - number of the affected CPU
|
||||
old - old frequency
|
||||
new - new frequency
|
||||
|
||||
3. CPUFreq Table Generation with Operating Performance Point (OPP)
|
||||
==================================================================
|
||||
For details about OPP, see Documentation/power/opp.txt
|
||||
|
||||
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
|
||||
cpufreq_frequency_table_cpuinfo which is provided with the list of
|
||||
frequencies that are available for operation. This function provides
|
||||
a ready to use conversion routine to translate the OPP layer's internal
|
||||
information about the available frequencies into a format readily
|
||||
providable to cpufreq.
|
||||
|
||||
WARNING: Do not use this function in interrupt context.
|
||||
|
||||
Example:
|
||||
soc_pm_init()
|
||||
{
|
||||
/* Do things */
|
||||
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
|
||||
if (!r)
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
/* Do other things */
|
||||
}
|
||||
|
||||
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
|
||||
addition to CONFIG_PM_OPP.
|
||||
|
||||
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table
|
||||
|
||||
@@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target
|
||||
stage. Just pass the values to this function, and the unsigned int
|
||||
index returns the number of the frequency table entry which contains
|
||||
the frequency the CPU shall be set to.
|
||||
|
||||
The following macros can be used as iterators over cpufreq_frequency_table:
|
||||
|
||||
cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
|
||||
table.
|
||||
|
||||
cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
|
||||
excluding CPUFREQ_ENTRY_INVALID frequencies.
|
||||
Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
|
||||
"table" - the cpufreq_frequency_table * you want to iterate over.
|
||||
|
||||
For example:
|
||||
|
||||
struct cpufreq_frequency_table *pos, *driver_freq_table;
|
||||
|
||||
cpufreq_for_each_entry(pos, driver_freq_table) {
|
||||
/* Do something with pos */
|
||||
pos->frequency = ...
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ Mailing List
|
||||
------------
|
||||
There is a CPU frequency changing CVS commit and general list where
|
||||
you can report bugs, problems or submit patches. To post a message,
|
||||
send an email to cpufreq@vger.kernel.org, to subscribe go to
|
||||
http://vger.kernel.org/vger-lists.html#cpufreq and follow the
|
||||
send an email to linux-pm@vger.kernel.org, to subscribe go to
|
||||
http://vger.kernel.org/vger-lists.html#linux-pm and follow the
|
||||
instructions there.
|
||||
|
||||
Links
|
||||
|
||||
@@ -10,8 +10,7 @@ Contents
|
||||
3. OPP Search Functions
|
||||
4. OPP Availability Control Functions
|
||||
5. OPP Data Retrieval Functions
|
||||
6. Cpufreq Table Generation
|
||||
7. Data Structures
|
||||
6. Data Structures
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
@@ -72,7 +71,6 @@ operations until that OPP could be re-enabled if possible.
|
||||
OPP library facilitates this concept in it's implementation. The following
|
||||
operational functions operate only on available opps:
|
||||
opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq, dev_pm_opp_get_opp_count
|
||||
and dev_pm_opp_init_cpufreq_table
|
||||
|
||||
dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then
|
||||
be used for dev_pm_opp_enable/disable functions to make an opp available as required.
|
||||
@@ -96,10 +94,9 @@ using RCU read locks. The opp_find_freq_{exact,ceil,floor},
|
||||
opp_get_{voltage, freq, opp_count} fall into this category.
|
||||
|
||||
opp_{add,enable,disable} are updaters which use mutex and implement it's own
|
||||
RCU locking mechanisms. dev_pm_opp_init_cpufreq_table acts as an updater and uses
|
||||
mutex to implment RCU updater strategy. These functions should *NOT* be called
|
||||
under RCU locks and other contexts that prevent blocking functions in RCU or
|
||||
mutex operations from working.
|
||||
RCU locking mechanisms. These functions should *NOT* be called under RCU locks
|
||||
and other contexts that prevent blocking functions in RCU or mutex operations
|
||||
from working.
|
||||
|
||||
2. Initial OPP List Registration
|
||||
================================
|
||||
@@ -311,34 +308,7 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
|
||||
/* Do other things */
|
||||
}
|
||||
|
||||
6. Cpufreq Table Generation
|
||||
===========================
|
||||
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
|
||||
cpufreq_frequency_table_cpuinfo which is provided with the list of
|
||||
frequencies that are available for operation. This function provides
|
||||
a ready to use conversion routine to translate the OPP layer's internal
|
||||
information about the available frequencies into a format readily
|
||||
providable to cpufreq.
|
||||
|
||||
WARNING: Do not use this function in interrupt context.
|
||||
|
||||
Example:
|
||||
soc_pm_init()
|
||||
{
|
||||
/* Do things */
|
||||
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
|
||||
if (!r)
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
/* Do other things */
|
||||
}
|
||||
|
||||
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
|
||||
addition to CONFIG_PM as power management feature is required to
|
||||
dynamically scale voltage and frequency in a system.
|
||||
|
||||
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table
|
||||
|
||||
7. Data Structures
|
||||
6. Data Structures
|
||||
==================
|
||||
Typically an SoC contains multiple voltage domains which are variable. Each
|
||||
domain is represented by a device pointer. The relationship to OPP can be
|
||||
|
||||
@@ -2410,7 +2410,6 @@ F: drivers/net/ethernet/ti/cpmac.c
|
||||
CPU FREQUENCY DRIVERS
|
||||
M: Rafael J. Wysocki <rjw@rjwysocki.net>
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
L: cpufreq@vger.kernel.org
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
|
||||
@@ -2421,7 +2420,6 @@ F: include/linux/cpufreq.h
|
||||
CPU FREQUENCY DRIVERS - ARM BIG LITTLE
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
L: cpufreq@vger.kernel.org
|
||||
L: linux-pm@vger.kernel.org
|
||||
W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
|
||||
S: Maintained
|
||||
|
||||
@@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk)
|
||||
|
||||
static int da850_round_armrate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
int i, ret = 0, diff;
|
||||
int ret = 0, diff;
|
||||
unsigned int best = (unsigned int) -1;
|
||||
struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
|
||||
rate /= 1000; /* convert to kHz */
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
diff = table[i].frequency - rate;
|
||||
cpufreq_for_each_entry(pos, table) {
|
||||
diff = pos->frequency - rate;
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
|
||||
if (diff < best) {
|
||||
best = diff;
|
||||
ret = table[i].frequency;
|
||||
ret = pos->frequency;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,10 +91,9 @@ EXPORT_SYMBOL(clk_put);
|
||||
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned int rate_khz = rate / 1000;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
int ret = 0;
|
||||
int regval;
|
||||
int i;
|
||||
|
||||
if (likely(clk->ops && clk->ops->set_rate)) {
|
||||
unsigned long flags;
|
||||
@@ -107,22 +106,16 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
|
||||
propagate_rate(clk);
|
||||
|
||||
for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
|
||||
i++) {
|
||||
if (loongson2_clockmod_table[i].frequency ==
|
||||
CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
if (rate_khz == loongson2_clockmod_table[i].frequency)
|
||||
cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table)
|
||||
if (rate == pos->frequency)
|
||||
break;
|
||||
}
|
||||
if (rate_khz != loongson2_clockmod_table[i].frequency)
|
||||
if (rate != pos->frequency)
|
||||
return -ENOTSUPP;
|
||||
|
||||
clk->rate = rate;
|
||||
|
||||
regval = LOONGSON_CHIPCFG0;
|
||||
regval = (regval & ~0x7) |
|
||||
(loongson2_clockmod_table[i].driver_data - 1);
|
||||
regval = (regval & ~0x7) | (pos->driver_data - 1);
|
||||
LOONGSON_CHIPCFG0 = regval;
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rculist.h>
|
||||
@@ -619,96 +618,6 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
/**
|
||||
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
|
||||
* @dev: device for which we do this operation
|
||||
* @table: Cpufreq table returned back to caller
|
||||
*
|
||||
* Generate a cpufreq table for a provided device- this assumes that the
|
||||
* opp list is already initialized and ready for usage.
|
||||
*
|
||||
* This function allocates required memory for the cpufreq table. It is
|
||||
* expected that the caller does the required maintenance such as freeing
|
||||
* the table as required.
|
||||
*
|
||||
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
|
||||
* if no memory available for the operation (table is not populated), returns 0
|
||||
* if successful and table is populated.
|
||||
*
|
||||
* WARNING: It is important for the callers to ensure refreshing their copy of
|
||||
* the table if any of the mentioned functions have been invoked in the interim.
|
||||
*
|
||||
* Locking: The internal device_opp and opp structures are RCU protected.
|
||||
* To simplify the logic, we pretend we are updater and hold relevant mutex here
|
||||
* Callers should ensure that this function is *NOT* called under RCU protection
|
||||
* or in contexts where mutex locking cannot be used.
|
||||
*/
|
||||
int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
{
|
||||
struct device_opp *dev_opp;
|
||||
struct dev_pm_opp *opp;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
int i = 0;
|
||||
|
||||
/* Pretend as if I am an updater */
|
||||
mutex_lock(&dev_opp_list_lock);
|
||||
|
||||
dev_opp = find_device_opp(dev);
|
||||
if (IS_ERR(dev_opp)) {
|
||||
int r = PTR_ERR(dev_opp);
|
||||
mutex_unlock(&dev_opp_list_lock);
|
||||
dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
|
||||
(dev_pm_opp_get_opp_count(dev) + 1), GFP_KERNEL);
|
||||
if (!freq_table) {
|
||||
mutex_unlock(&dev_opp_list_lock);
|
||||
dev_warn(dev, "%s: Unable to allocate frequency table\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list_for_each_entry(opp, &dev_opp->opp_list, node) {
|
||||
if (opp->available) {
|
||||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = opp->rate / 1000;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev_opp_list_lock);
|
||||
|
||||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
*table = &freq_table[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
|
||||
* @dev: device for which we do this operation
|
||||
* @table: table to free
|
||||
*
|
||||
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
|
||||
*/
|
||||
void dev_pm_opp_free_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
kfree(*table);
|
||||
*table = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
|
||||
#endif /* CONFIG_CPU_FREQ */
|
||||
|
||||
/**
|
||||
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp
|
||||
* @dev: device pointer used to lookup device OPPs.
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
# big LITTLE core layer and glue drivers
|
||||
config ARM_BIG_LITTLE_CPUFREQ
|
||||
tristate "Generic ARM big LITTLE CPUfreq driver"
|
||||
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
|
||||
depends on (BIG_LITTLE && ARM_CPU_TOPOLOGY) || (ARM64 && SMP)
|
||||
depends on HAVE_CLK
|
||||
select PM_OPP
|
||||
help
|
||||
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
|
||||
@@ -85,7 +86,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
|
||||
It allows usage of special frequencies for Samsung Exynos
|
||||
processors if thermal conditions are appropriate.
|
||||
|
||||
It reguires, for safe operation, thermal framework with properly
|
||||
It requires, for safe operation, thermal framework with properly
|
||||
defined trip points.
|
||||
|
||||
If in doubt, say N.
|
||||
@@ -186,7 +187,7 @@ config ARM_S3C2416_CPUFREQ
|
||||
S3C2450 SoC. The S3C2416 supports changing the rate of the
|
||||
armdiv clock source and also entering a so called dynamic
|
||||
voltage scaling mode in which it is possible to reduce the
|
||||
core voltage of the cpu.
|
||||
core voltage of the CPU.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ config X86_INTEL_PSTATE
|
||||
The driver implements an internal governor and will become
|
||||
the scaling driver and governor for Sandy bridge processors.
|
||||
|
||||
When this driver is enabled it will become the perferred
|
||||
When this driver is enabled it will become the preferred
|
||||
scaling driver for Sandy bridge processors.
|
||||
|
||||
If in doubt, say N.
|
||||
@@ -52,7 +52,7 @@ config X86_ACPI_CPUFREQ_CPB
|
||||
help
|
||||
The powernow-k8 driver used to provide a sysfs knob called "cpb"
|
||||
to disable the Core Performance Boosting feature of AMD CPUs. This
|
||||
file has now been superseeded by the more generic "boost" entry.
|
||||
file has now been superseded by the more generic "boost" entry.
|
||||
|
||||
By enabling this option the acpi_cpufreq driver provides the old
|
||||
entry in addition to the new boost ones, for compatibility reasons.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# CPUfreq core
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
|
||||
obj-$(CONFIG_PM_OPP) += cpufreq_opp.o
|
||||
|
||||
# CPUfreq stats
|
||||
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
|
||||
|
||||
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
struct acpi_processor_performance *perf;
|
||||
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
||||
@@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
|
||||
|
||||
perf = data->acpi_data;
|
||||
|
||||
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
if (msr == perf->states[data->freq_table[i].driver_data].status)
|
||||
return data->freq_table[i].frequency;
|
||||
}
|
||||
cpufreq_for_each_entry(pos, data->freq_table)
|
||||
if (msr == perf->states[pos->driver_data].status)
|
||||
return pos->frequency;
|
||||
return data->freq_table[0].frequency;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
|
||||
/* get the minimum frequency in the cpufreq_frequency_table */
|
||||
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
uint32_t min_freq = ~0;
|
||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
|
||||
if (table[i].frequency < min_freq)
|
||||
min_freq = table[i].frequency;
|
||||
cpufreq_for_each_entry(pos, table)
|
||||
if (pos->frequency < min_freq)
|
||||
min_freq = pos->frequency;
|
||||
return min_freq;
|
||||
}
|
||||
|
||||
/* get the maximum frequency in the cpufreq_frequency_table */
|
||||
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
uint32_t max_freq = 0;
|
||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
|
||||
if (table[i].frequency > max_freq)
|
||||
max_freq = table[i].frequency;
|
||||
cpufreq_for_each_entry(pos, table)
|
||||
if (pos->frequency > max_freq)
|
||||
max_freq = pos->frequency;
|
||||
return max_freq;
|
||||
}
|
||||
|
||||
|
||||
@@ -379,7 +379,7 @@ static struct cpufreq_driver nforce2_driver = {
|
||||
};
|
||||
|
||||
#ifdef MODULE
|
||||
static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
|
||||
static const struct pci_device_id nforce2_ids[] = {
|
||||
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
|
||||
{}
|
||||
};
|
||||
|
||||
+47
-23
@@ -354,6 +354,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
|
||||
void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs)
|
||||
{
|
||||
|
||||
/*
|
||||
* Catch double invocations of _begin() which lead to self-deadlock.
|
||||
* ASYNC_NOTIFICATION drivers are left out because the cpufreq core
|
||||
* doesn't invoke _begin() on their behalf, and hence the chances of
|
||||
* double invocations are very low. Moreover, there are scenarios
|
||||
* where these checks can emit false-positive warnings in these
|
||||
* drivers; so we avoid that by skipping them altogether.
|
||||
*/
|
||||
WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION)
|
||||
&& current == policy->transition_task);
|
||||
|
||||
wait:
|
||||
wait_event(policy->transition_wait, !policy->transition_ongoing);
|
||||
|
||||
@@ -365,6 +377,7 @@ wait:
|
||||
}
|
||||
|
||||
policy->transition_ongoing = true;
|
||||
policy->transition_task = current;
|
||||
|
||||
spin_unlock(&policy->transition_lock);
|
||||
|
||||
@@ -381,6 +394,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
|
||||
cpufreq_notify_post_transition(policy, freqs, transition_failed);
|
||||
|
||||
policy->transition_ongoing = false;
|
||||
policy->transition_task = NULL;
|
||||
|
||||
wake_up(&policy->transition_wait);
|
||||
}
|
||||
@@ -1802,12 +1816,43 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
|
||||
* GOVERNORS *
|
||||
*********************************************************************/
|
||||
|
||||
static int __target_index(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *freq_table, int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
int retval = -EINVAL;
|
||||
bool notify;
|
||||
|
||||
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
|
||||
|
||||
if (notify) {
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = freq_table[index].frequency;
|
||||
freqs.flags = 0;
|
||||
|
||||
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
|
||||
__func__, policy->cpu, freqs.old, freqs.new);
|
||||
|
||||
cpufreq_freq_transition_begin(policy, &freqs);
|
||||
}
|
||||
|
||||
retval = cpufreq_driver->target_index(policy, index);
|
||||
if (retval)
|
||||
pr_err("%s: Failed to change cpu frequency: %d\n", __func__,
|
||||
retval);
|
||||
|
||||
if (notify)
|
||||
cpufreq_freq_transition_end(policy, &freqs, retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
unsigned int old_target_freq = target_freq;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return -ENODEV;
|
||||
@@ -1834,8 +1879,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
retval = cpufreq_driver->target(policy, target_freq, relation);
|
||||
else if (cpufreq_driver->target_index) {
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
struct cpufreq_freqs freqs;
|
||||
bool notify;
|
||||
int index;
|
||||
|
||||
freq_table = cpufreq_frequency_get_table(policy->cpu);
|
||||
@@ -1856,26 +1899,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
goto out;
|
||||
}
|
||||
|
||||
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
|
||||
|
||||
if (notify) {
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = freq_table[index].frequency;
|
||||
freqs.flags = 0;
|
||||
|
||||
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
|
||||
__func__, policy->cpu, freqs.old, freqs.new);
|
||||
|
||||
cpufreq_freq_transition_begin(policy, &freqs);
|
||||
}
|
||||
|
||||
retval = cpufreq_driver->target_index(policy, index);
|
||||
if (retval)
|
||||
pr_err("%s: Failed to change cpu frequency: %d\n",
|
||||
__func__, retval);
|
||||
|
||||
if (notify)
|
||||
cpufreq_freq_transition_end(policy, &freqs, retval);
|
||||
retval = __target_index(policy, freq_table, index);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Generic OPP helper interface for CPUFreq drivers
|
||||
*
|
||||
* Copyright (C) 2009-2014 Texas Instruments Incorporated.
|
||||
* Nishanth Menon
|
||||
* Romit Dasgupta
|
||||
* Kevin Hilman
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
|
||||
* @dev: device for which we do this operation
|
||||
* @table: Cpufreq table returned back to caller
|
||||
*
|
||||
* Generate a cpufreq table for a provided device- this assumes that the
|
||||
* opp list is already initialized and ready for usage.
|
||||
*
|
||||
* This function allocates required memory for the cpufreq table. It is
|
||||
* expected that the caller does the required maintenance such as freeing
|
||||
* the table as required.
|
||||
*
|
||||
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
|
||||
* if no memory available for the operation (table is not populated), returns 0
|
||||
* if successful and table is populated.
|
||||
*
|
||||
* WARNING: It is important for the callers to ensure refreshing their copy of
|
||||
* the table if any of the mentioned functions have been invoked in the interim.
|
||||
*
|
||||
* Locking: The internal device_opp and opp structures are RCU protected.
|
||||
* Since we just use the regular accessor functions to access the internal data
|
||||
* structures, we use RCU read lock inside this function. As a result, users of
|
||||
* this function DONOT need to use explicit locks for invoking.
|
||||
*/
|
||||
int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
struct cpufreq_frequency_table *freq_table = NULL;
|
||||
int i, max_opps, ret = 0;
|
||||
unsigned long rate;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
max_opps = dev_pm_opp_get_opp_count(dev);
|
||||
if (max_opps <= 0) {
|
||||
ret = max_opps ? max_opps : -ENODATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
|
||||
if (!freq_table) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
|
||||
/* find next rate */
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &rate);
|
||||
if (IS_ERR(opp)) {
|
||||
ret = PTR_ERR(opp);
|
||||
goto out;
|
||||
}
|
||||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = rate / 1000;
|
||||
}
|
||||
|
||||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
*table = &freq_table[0];
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
if (ret)
|
||||
kfree(freq_table);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
|
||||
* @dev: device for which we do this operation
|
||||
* @table: table to free
|
||||
*
|
||||
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
|
||||
*/
|
||||
void dev_pm_opp_free_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
kfree(*table);
|
||||
*table = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
|
||||
@@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
|
||||
|
||||
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i, j, count = 0, ret = 0;
|
||||
unsigned int i, count = 0, ret = 0;
|
||||
struct cpufreq_stats *stat;
|
||||
unsigned int alloc_size;
|
||||
unsigned int cpu = policy->cpu;
|
||||
struct cpufreq_frequency_table *table;
|
||||
struct cpufreq_frequency_table *pos, *table;
|
||||
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (unlikely(!table))
|
||||
@@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||
stat->cpu = cpu;
|
||||
per_cpu(cpufreq_stats_table, cpu) = stat;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
unsigned int freq = table[i].frequency;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
cpufreq_for_each_valid_entry(pos, table)
|
||||
count++;
|
||||
}
|
||||
|
||||
alloc_size = count * sizeof(int) + count * sizeof(u64);
|
||||
|
||||
@@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
stat->trans_table = stat->freq_table + count;
|
||||
#endif
|
||||
j = 0;
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
unsigned int freq = table[i].frequency;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
if (freq_table_get_index(stat, freq) == -1)
|
||||
stat->freq_table[j++] = freq;
|
||||
}
|
||||
stat->state_num = j;
|
||||
i = 0;
|
||||
cpufreq_for_each_valid_entry(pos, table)
|
||||
if (freq_table_get_index(stat, pos->frequency) == -1)
|
||||
stat->freq_table[i++] = pos->frequency;
|
||||
stat->state_num = i;
|
||||
spin_lock(&cpufreq_stats_lock);
|
||||
stat->last_time = get_jiffies_64();
|
||||
stat->last_index = freq_table_get_index(stat, policy->cur);
|
||||
|
||||
@@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
|
||||
|
||||
static int dbx500_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i = 0;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
|
||||
freq_table = dev_get_platdata(&pdev->dev);
|
||||
if (!freq_table) {
|
||||
@@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
pr_info("dbx500-cpufreq: Available frequencies:\n");
|
||||
while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
|
||||
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
|
||||
i++;
|
||||
}
|
||||
cpufreq_for_each_entry(pos, freq_table)
|
||||
pr_info(" %d Mhz\n", pos->frequency / 1000);
|
||||
|
||||
return cpufreq_register_driver(&dbx500_cpufreq_driver);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
|
||||
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
unsigned int i;
|
||||
struct cpufreq_frequency_table *pos;
|
||||
|
||||
/* capability check */
|
||||
if ((c->x86_vendor != X86_VENDOR_AMD) ||
|
||||
@@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
|
||||
max_freq = elanfreq_get_cpu_frequency(0);
|
||||
|
||||
/* table init */
|
||||
for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if (elanfreq_table[i].frequency > max_freq)
|
||||
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
}
|
||||
cpufreq_for_each_entry(pos, elanfreq_table)
|
||||
if (pos->frequency > max_freq)
|
||||
pos->frequency = CPUFREQ_ENTRY_INVALID;
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user