Skip to content

Commit a0dd7b7

Browse files
nmenonrafaeljw
authored andcommitted
PM / OPP: Move cpufreq specific OPP functions out of generic OPP library
CPUFreq specific helper functions for OPP (Operating Performance Points) now use generic OPP functions that allow CPUFreq to be be moved back into CPUFreq framework. This allows for independent modifications or future enhancements as needed isolated to just CPUFreq framework alone. Here, we just move relevant code and documentation to make this part of CPUFreq infrastructure. Cc: Kevin Hilman <[email protected]> Signed-off-by: Nishanth Menon <[email protected]> Acked-by: Viresh Kumar <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 0f5c890 commit a0dd7b7

File tree

7 files changed

+167
-147
lines changed

7 files changed

+167
-147
lines changed

Documentation/cpu-freq/core.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Contents:
2020
---------
2121
1. CPUFreq core and interfaces
2222
2. CPUFreq notifiers
23+
3. CPUFreq Table Generation with Operating Performance Point (OPP)
2324

2425
1. General Information
2526
=======================
@@ -92,3 +93,31 @@ values:
9293
cpu - number of the affected CPU
9394
old - old frequency
9495
new - new frequency
96+
97+
3. CPUFreq Table Generation with Operating Performance Point (OPP)
98+
==================================================================
99+
For details about OPP, see Documentation/power/opp.txt
100+
101+
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
102+
cpufreq_frequency_table_cpuinfo which is provided with the list of
103+
frequencies that are available for operation. This function provides
104+
a ready to use conversion routine to translate the OPP layer's internal
105+
information about the available frequencies into a format readily
106+
providable to cpufreq.
107+
108+
WARNING: Do not use this function in interrupt context.
109+
110+
Example:
111+
soc_pm_init()
112+
{
113+
/* Do things */
114+
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
115+
if (!r)
116+
cpufreq_frequency_table_cpuinfo(policy, freq_table);
117+
/* Do other things */
118+
}
119+
120+
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
121+
addition to CONFIG_PM_OPP.
122+
123+
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table

Documentation/power/opp.txt

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ Contents
1010
3. OPP Search Functions
1111
4. OPP Availability Control Functions
1212
5. OPP Data Retrieval Functions
13-
6. Cpufreq Table Generation
14-
7. Data Structures
13+
6. Data Structures
1514

1615
1. Introduction
1716
===============
@@ -72,7 +71,6 @@ operations until that OPP could be re-enabled if possible.
7271
OPP library facilitates this concept in it's implementation. The following
7372
operational functions operate only on available opps:
7473
opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq, dev_pm_opp_get_opp_count
75-
and dev_pm_opp_init_cpufreq_table
7674

7775
dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then
7876
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},
9694
opp_get_{voltage, freq, opp_count} fall into this category.
9795

9896
opp_{add,enable,disable} are updaters which use mutex and implement it's own
99-
RCU locking mechanisms. dev_pm_opp_init_cpufreq_table acts as an updater and uses
100-
mutex to implment RCU updater strategy. These functions should *NOT* be called
101-
under RCU locks and other contexts that prevent blocking functions in RCU or
102-
mutex operations from working.
97+
RCU locking mechanisms. These functions should *NOT* be called under RCU locks
98+
and other contexts that prevent blocking functions in RCU or mutex operations
99+
from working.
103100

104101
2. Initial OPP List Registration
105102
================================
@@ -311,34 +308,7 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
311308
/* Do other things */
312309
}
313310

314-
6. Cpufreq Table Generation
315-
===========================
316-
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
317-
cpufreq_frequency_table_cpuinfo which is provided with the list of
318-
frequencies that are available for operation. This function provides
319-
a ready to use conversion routine to translate the OPP layer's internal
320-
information about the available frequencies into a format readily
321-
providable to cpufreq.
322-
323-
WARNING: Do not use this function in interrupt context.
324-
325-
Example:
326-
soc_pm_init()
327-
{
328-
/* Do things */
329-
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
330-
if (!r)
331-
cpufreq_frequency_table_cpuinfo(policy, freq_table);
332-
/* Do other things */
333-
}
334-
335-
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
336-
addition to CONFIG_PM as power management feature is required to
337-
dynamically scale voltage and frequency in a system.
338-
339-
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table
340-
341-
7. Data Structures
311+
6. Data Structures
342312
==================
343313
Typically an SoC contains multiple voltage domains which are variable. Each
344314
domain is represented by a device pointer. The relationship to OPP can be

drivers/base/power/opp.c

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include <linux/errno.h>
1616
#include <linux/err.h>
1717
#include <linux/slab.h>
18-
#include <linux/cpufreq.h>
1918
#include <linux/device.h>
2019
#include <linux/list.h>
2120
#include <linux/rculist.h>
@@ -596,97 +595,6 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq)
596595
}
597596
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
598597

599-
#ifdef CONFIG_CPU_FREQ
600-
/**
601-
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
602-
* @dev: device for which we do this operation
603-
* @table: Cpufreq table returned back to caller
604-
*
605-
* Generate a cpufreq table for a provided device- this assumes that the
606-
* opp list is already initialized and ready for usage.
607-
*
608-
* This function allocates required memory for the cpufreq table. It is
609-
* expected that the caller does the required maintenance such as freeing
610-
* the table as required.
611-
*
612-
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
613-
* if no memory available for the operation (table is not populated), returns 0
614-
* if successful and table is populated.
615-
*
616-
* WARNING: It is important for the callers to ensure refreshing their copy of
617-
* the table if any of the mentioned functions have been invoked in the interim.
618-
*
619-
* Locking: The internal device_opp and opp structures are RCU protected.
620-
* Since we just use the regular accessor functions to access the internal data
621-
* structures, we use RCU read lock inside this function. As a result, users of
622-
* this function DONOT need to use explicit locks for invoking.
623-
*/
624-
int dev_pm_opp_init_cpufreq_table(struct device *dev,
625-
struct cpufreq_frequency_table **table)
626-
{
627-
struct dev_pm_opp *opp;
628-
struct cpufreq_frequency_table *freq_table = NULL;
629-
int i, max_opps, ret = 0;
630-
unsigned long rate;
631-
632-
rcu_read_lock();
633-
634-
max_opps = dev_pm_opp_get_opp_count(dev);
635-
if (max_opps <= 0) {
636-
ret = max_opps ? max_opps : -ENODATA;
637-
goto out;
638-
}
639-
640-
freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
641-
if (!freq_table) {
642-
ret = -ENOMEM;
643-
goto out;
644-
}
645-
646-
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
647-
/* find next rate */
648-
opp = dev_pm_opp_find_freq_ceil(dev, &rate);
649-
if (IS_ERR(opp)) {
650-
ret = PTR_ERR(opp);
651-
goto out;
652-
}
653-
freq_table[i].driver_data = i;
654-
freq_table[i].frequency = rate / 1000;
655-
}
656-
657-
freq_table[i].driver_data = i;
658-
freq_table[i].frequency = CPUFREQ_TABLE_END;
659-
660-
*table = &freq_table[0];
661-
662-
out:
663-
rcu_read_unlock();
664-
if (ret)
665-
kfree(freq_table);
666-
667-
return ret;
668-
}
669-
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
670-
671-
/**
672-
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
673-
* @dev: device for which we do this operation
674-
* @table: table to free
675-
*
676-
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
677-
*/
678-
void dev_pm_opp_free_cpufreq_table(struct device *dev,
679-
struct cpufreq_frequency_table **table)
680-
{
681-
if (!table)
682-
return;
683-
684-
kfree(*table);
685-
*table = NULL;
686-
}
687-
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
688-
#endif /* CONFIG_CPU_FREQ */
689-
690598
/**
691599
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp
692600
* @dev: device pointer used to lookup device OPPs.

drivers/cpufreq/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# CPUfreq core
22
obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
3+
obj-$(CONFIG_PM_OPP) += cpufreq_opp.o
4+
35
# CPUfreq stats
46
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
57

drivers/cpufreq/cpufreq_opp.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Generic OPP helper interface for CPUFreq drivers
3+
*
4+
* Copyright (C) 2009-2014 Texas Instruments Incorporated.
5+
* Nishanth Menon
6+
* Romit Dasgupta
7+
* Kevin Hilman
8+
*
9+
* This program is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License version 2 as
11+
* published by the Free Software Foundation.
12+
*/
13+
#include <linux/cpufreq.h>
14+
#include <linux/device.h>
15+
#include <linux/err.h>
16+
#include <linux/errno.h>
17+
#include <linux/export.h>
18+
#include <linux/kernel.h>
19+
#include <linux/pm_opp.h>
20+
#include <linux/rcupdate.h>
21+
#include <linux/slab.h>
22+
23+
/**
24+
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
25+
* @dev: device for which we do this operation
26+
* @table: Cpufreq table returned back to caller
27+
*
28+
* Generate a cpufreq table for a provided device- this assumes that the
29+
* opp list is already initialized and ready for usage.
30+
*
31+
* This function allocates required memory for the cpufreq table. It is
32+
* expected that the caller does the required maintenance such as freeing
33+
* the table as required.
34+
*
35+
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
36+
* if no memory available for the operation (table is not populated), returns 0
37+
* if successful and table is populated.
38+
*
39+
* WARNING: It is important for the callers to ensure refreshing their copy of
40+
* the table if any of the mentioned functions have been invoked in the interim.
41+
*
42+
* Locking: The internal device_opp and opp structures are RCU protected.
43+
* Since we just use the regular accessor functions to access the internal data
44+
* structures, we use RCU read lock inside this function. As a result, users of
45+
* this function DONOT need to use explicit locks for invoking.
46+
*/
47+
int dev_pm_opp_init_cpufreq_table(struct device *dev,
48+
struct cpufreq_frequency_table **table)
49+
{
50+
struct dev_pm_opp *opp;
51+
struct cpufreq_frequency_table *freq_table = NULL;
52+
int i, max_opps, ret = 0;
53+
unsigned long rate;
54+
55+
rcu_read_lock();
56+
57+
max_opps = dev_pm_opp_get_opp_count(dev);
58+
if (max_opps <= 0) {
59+
ret = max_opps ? max_opps : -ENODATA;
60+
goto out;
61+
}
62+
63+
freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
64+
if (!freq_table) {
65+
ret = -ENOMEM;
66+
goto out;
67+
}
68+
69+
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
70+
/* find next rate */
71+
opp = dev_pm_opp_find_freq_ceil(dev, &rate);
72+
if (IS_ERR(opp)) {
73+
ret = PTR_ERR(opp);
74+
goto out;
75+
}
76+
freq_table[i].driver_data = i;
77+
freq_table[i].frequency = rate / 1000;
78+
}
79+
80+
freq_table[i].driver_data = i;
81+
freq_table[i].frequency = CPUFREQ_TABLE_END;
82+
83+
*table = &freq_table[0];
84+
85+
out:
86+
rcu_read_unlock();
87+
if (ret)
88+
kfree(freq_table);
89+
90+
return ret;
91+
}
92+
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
93+
94+
/**
95+
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
96+
* @dev: device for which we do this operation
97+
* @table: table to free
98+
*
99+
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
100+
*/
101+
void dev_pm_opp_free_cpufreq_table(struct device *dev,
102+
struct cpufreq_frequency_table **table)
103+
{
104+
if (!table)
105+
return;
106+
107+
kfree(*table);
108+
*table = NULL;
109+
}
110+
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);

include/linux/cpufreq.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,27 @@ struct cpufreq_frequency_table {
469469
* order */
470470
};
471471

472+
#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
473+
int dev_pm_opp_init_cpufreq_table(struct device *dev,
474+
struct cpufreq_frequency_table **table);
475+
void dev_pm_opp_free_cpufreq_table(struct device *dev,
476+
struct cpufreq_frequency_table **table);
477+
#else
478+
static inline int dev_pm_opp_init_cpufreq_table(struct device *dev,
479+
struct cpufreq_frequency_table
480+
**table)
481+
{
482+
return -EINVAL;
483+
}
484+
485+
static inline void dev_pm_opp_free_cpufreq_table(struct device *dev,
486+
struct cpufreq_frequency_table
487+
**table)
488+
{
489+
}
490+
#endif
491+
492+
472493
bool cpufreq_next_valid(struct cpufreq_frequency_table **pos);
473494

474495
/*

include/linux/pm_opp.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#define __LINUX_OPP_H__
1616

1717
#include <linux/err.h>
18-
#include <linux/cpufreq.h>
1918
#include <linux/notifier.h>
2019

2120
struct dev_pm_opp;
@@ -117,23 +116,4 @@ static inline int of_init_opp_table(struct device *dev)
117116
}
118117
#endif
119118

120-
#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
121-
int dev_pm_opp_init_cpufreq_table(struct device *dev,
122-
struct cpufreq_frequency_table **table);
123-
void dev_pm_opp_free_cpufreq_table(struct device *dev,
124-
struct cpufreq_frequency_table **table);
125-
#else
126-
static inline int dev_pm_opp_init_cpufreq_table(struct device *dev,
127-
struct cpufreq_frequency_table **table)
128-
{
129-
return -EINVAL;
130-
}
131-
132-
static inline
133-
void dev_pm_opp_free_cpufreq_table(struct device *dev,
134-
struct cpufreq_frequency_table **table)
135-
{
136-
}
137-
#endif /* CONFIG_CPU_FREQ */
138-
139119
#endif /* __LINUX_OPP_H__ */

0 commit comments

Comments
 (0)