Commit 37c14794 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge back earlier 'pm-cpufreq' material.

parents 89ca3b88 a0dd7b79
......@@ -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
......
......@@ -2415,7 +2415,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
......@@ -2426,7 +2425,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,9 +91,9 @@ EXPORT_SYMBOL(clk_put);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
struct cpufreq_frequency_table *pos;
int ret = 0;
int regval;
int i;
if (likely(clk->ops && clk->ops->set_rate)) {
unsigned long flags;
......@@ -106,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 == loongson2_clockmod_table[i].frequency)
cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table)
if (rate == pos->frequency)
break;
}
if (rate != 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>
......@@ -596,96 +595,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.
......
......@@ -85,7 +85,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 +186,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.
......
# 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;
}
......
......@@ -237,6 +237,17 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy)
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos)
{
while ((*pos)->frequency != CPUFREQ_TABLE_END)
if ((*pos)->frequency != CPUFREQ_ENTRY_INVALID)
return true;
else
(*pos)++;
return false;
}
EXPORT_SYMBOL_GPL(cpufreq_next_valid);
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
......@@ -354,6 +365,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 +388,7 @@ void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
}
policy->transition_ongoing = true;
policy->transition_task = current;
spin_unlock(&policy->transition_lock);
......@@ -381,6 +405,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);
}
......
/*
* 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)