aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2015-09-04 04:17:26 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-09-14 20:03:16 -0400
commitf59d3ee8480d30f41914cb4bed5086237e8507b0 (patch)
tree06c8cea1e5d4eaa0cf94769edc892fa8ec386655 /drivers/base
parent33692dc381f9b89ddfc408631bf670ac2fd08ffc (diff)
PM / OPP: Move cpu specific code to opp/cpu.c
Move cpu device specific code out of generic opp library, and add it to cpu.c. Along with that, create a core-internal opp.h header, which will be used to share structures and function prototypes within opp core. Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/opp/core.c276
-rw-r--r--drivers/base/power/opp/cpu.c160
-rw-r--r--drivers/base/power/opp/opp.h143
3 files changed, 304 insertions, 275 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index aeff1cfb46f2..a731fa66e504 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -11,131 +11,14 @@
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13 13
14#include <linux/cpu.h>
15#include <linux/kernel.h>
16#include <linux/errno.h> 14#include <linux/errno.h>
17#include <linux/err.h> 15#include <linux/err.h>
18#include <linux/slab.h> 16#include <linux/slab.h>
19#include <linux/device.h> 17#include <linux/device.h>
20#include <linux/list.h>
21#include <linux/rculist.h>
22#include <linux/rcupdate.h>
23#include <linux/pm_opp.h>
24#include <linux/of.h> 18#include <linux/of.h>
25#include <linux/export.h> 19#include <linux/export.h>
26 20
27/* 21#include "opp.h"
28 * Internal data structure organization with the OPP layer library is as
29 * follows:
30 * dev_opp_list (root)
31 * |- device 1 (represents voltage domain 1)
32 * | |- opp 1 (availability, freq, voltage)
33 * | |- opp 2 ..
34 * ... ...
35 * | `- opp n ..
36 * |- device 2 (represents the next voltage domain)
37 * ...
38 * `- device m (represents mth voltage domain)
39 * device 1, 2.. are represented by dev_opp structure while each opp
40 * is represented by the opp structure.
41 */
42
43/**
44 * struct dev_pm_opp - Generic OPP description structure
45 * @node: opp list node. The nodes are maintained throughout the lifetime
46 * of boot. It is expected only an optimal set of OPPs are
47 * added to the library by the SoC framework.
48 * RCU usage: opp list is traversed with RCU locks. node
49 * modification is possible realtime, hence the modifications
50 * are protected by the dev_opp_list_lock for integrity.
51 * IMPORTANT: the opp nodes should be maintained in increasing
52 * order.
53 * @dynamic: not-created from static DT entries.
54 * @available: true/false - marks if this OPP as available or not
55 * @turbo: true if turbo (boost) OPP
56 * @rate: Frequency in hertz
57 * @u_volt: Target voltage in microvolts corresponding to this OPP
58 * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
59 * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
60 * @u_amp: Maximum current drawn by the device in microamperes
61 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
62 * frequency from any other OPP's frequency.
63 * @dev_opp: points back to the device_opp struct this opp belongs to
64 * @rcu_head: RCU callback head used for deferred freeing
65 * @np: OPP's device node.
66 *
67 * This structure stores the OPP information for a given device.
68 */
69struct dev_pm_opp {
70 struct list_head node;
71
72 bool available;
73 bool dynamic;
74 bool turbo;
75 unsigned long rate;
76
77 unsigned long u_volt;
78 unsigned long u_volt_min;
79 unsigned long u_volt_max;
80 unsigned long u_amp;
81 unsigned long clock_latency_ns;
82
83 struct device_opp *dev_opp;
84 struct rcu_head rcu_head;
85
86 struct device_node *np;
87};
88
89/**
90 * struct device_list_opp - devices managed by 'struct device_opp'
91 * @node: list node
92 * @dev: device to which the struct object belongs
93 * @rcu_head: RCU callback head used for deferred freeing
94 *
95 * This is an internal data structure maintaining the list of devices that are
96 * managed by 'struct device_opp'.
97 */
98struct device_list_opp {
99 struct list_head node;
100 const struct device *dev;
101 struct rcu_head rcu_head;
102};
103
104/**
105 * struct device_opp - Device opp structure
106 * @node: list node - contains the devices with OPPs that
107 * have been registered. Nodes once added are not modified in this
108 * list.
109 * RCU usage: nodes are not modified in the list of device_opp,
110 * however addition is possible and is secured by dev_opp_list_lock
111 * @srcu_head: notifier head to notify the OPP availability changes.
112 * @rcu_head: RCU callback head used for deferred freeing
113 * @dev_list: list of devices that share these OPPs
114 * @opp_list: list of opps
115 * @np: struct device_node pointer for opp's DT node.
116 * @shared_opp: OPP is shared between multiple devices.
117 *
118 * This is an internal data structure maintaining the link to opps attached to
119 * a device. This structure is not meant to be shared to users as it is
120 * meant for book keeping and private to OPP library.
121 *
122 * Because the opp structures can be used from both rcu and srcu readers, we
123 * need to wait for the grace period of both of them before freeing any
124 * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
125 */
126struct device_opp {
127 struct list_head node;
128
129 struct srcu_notifier_head srcu_head;
130 struct rcu_head rcu_head;
131 struct list_head dev_list;
132 struct list_head opp_list;
133
134 struct device_node *np;
135 unsigned long clock_latency_ns_max;
136 bool shared_opp;
137 struct dev_pm_opp *suspend_opp;
138};
139 22
140/* 23/*
141 * The root of the list of all devices. All device_opp structures branch off 24 * The root of the list of all devices. All device_opp structures branch off
@@ -200,7 +83,7 @@ static struct device_opp *_managed_opp(const struct device_node *np)
200 * is a RCU protected pointer. This means that device_opp is valid as long 83 * is a RCU protected pointer. This means that device_opp is valid as long
201 * as we are under RCU lock. 84 * as we are under RCU lock.
202 */ 85 */
203static struct device_opp *_find_device_opp(struct device *dev) 86struct device_opp *_find_device_opp(struct device *dev)
204{ 87{
205 struct device_opp *dev_opp; 88 struct device_opp *dev_opp;
206 89
@@ -579,8 +462,8 @@ static void _remove_list_dev(struct device_list_opp *list_dev,
579 _kfree_list_dev_rcu); 462 _kfree_list_dev_rcu);
580} 463}
581 464
582static struct device_list_opp *_add_list_dev(const struct device *dev, 465struct device_list_opp *_add_list_dev(const struct device *dev,
583 struct device_opp *dev_opp) 466 struct device_opp *dev_opp)
584{ 467{
585 struct device_list_opp *list_dev; 468 struct device_list_opp *list_dev;
586 469
@@ -1262,28 +1145,8 @@ unlock:
1262} 1145}
1263EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); 1146EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
1264 1147
1265void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask)
1266{
1267 struct device *cpu_dev;
1268 int cpu;
1269
1270 WARN_ON(cpumask_empty(cpumask));
1271
1272 for_each_cpu(cpu, cpumask) {
1273 cpu_dev = get_cpu_device(cpu);
1274 if (!cpu_dev) {
1275 pr_err("%s: failed to get cpu%d device\n", __func__,
1276 cpu);
1277 continue;
1278 }
1279
1280 dev_pm_opp_of_remove_table(cpu_dev);
1281 }
1282}
1283EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
1284
1285/* Returns opp descriptor node for a device, caller must do of_node_put() */ 1148/* Returns opp descriptor node for a device, caller must do of_node_put() */
1286static struct device_node *_of_get_opp_desc_node(struct device *dev) 1149struct device_node *_of_get_opp_desc_node(struct device *dev)
1287{ 1150{
1288 /* 1151 /*
1289 * TODO: Support for multiple OPP tables. 1152 * TODO: Support for multiple OPP tables.
@@ -1427,133 +1290,4 @@ int dev_pm_opp_of_add_table(struct device *dev)
1427 return ret; 1290 return ret;
1428} 1291}
1429EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); 1292EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
1430
1431int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask)
1432{
1433 struct device *cpu_dev;
1434 int cpu, ret = 0;
1435
1436 WARN_ON(cpumask_empty(cpumask));
1437
1438 for_each_cpu(cpu, cpumask) {
1439 cpu_dev = get_cpu_device(cpu);
1440 if (!cpu_dev) {
1441 pr_err("%s: failed to get cpu%d device\n", __func__,
1442 cpu);
1443 continue;
1444 }
1445
1446 ret = dev_pm_opp_of_add_table(cpu_dev);
1447 if (ret) {
1448 pr_err("%s: couldn't find opp table for cpu:%d, %d\n",
1449 __func__, cpu, ret);
1450
1451 /* Free all other OPPs */
1452 dev_pm_opp_of_cpumask_remove_table(cpumask);
1453 break;
1454 }
1455 }
1456
1457 return ret;
1458}
1459EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
1460
1461/* Required only for V1 bindings, as v2 can manage it from DT itself */
1462int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
1463{
1464 struct device_list_opp *list_dev;
1465 struct device_opp *dev_opp;
1466 struct device *dev;
1467 int cpu, ret = 0;
1468
1469 rcu_read_lock();
1470
1471 dev_opp = _find_device_opp(cpu_dev);
1472 if (IS_ERR(dev_opp)) {
1473 ret = -EINVAL;
1474 goto out_rcu_read_unlock;
1475 }
1476
1477 for_each_cpu(cpu, cpumask) {
1478 if (cpu == cpu_dev->id)
1479 continue;
1480
1481 dev = get_cpu_device(cpu);
1482 if (!dev) {
1483 dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
1484 __func__, cpu);
1485 continue;
1486 }
1487
1488 list_dev = _add_list_dev(dev, dev_opp);
1489 if (!list_dev) {
1490 dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
1491 __func__, cpu);
1492 continue;
1493 }
1494 }
1495out_rcu_read_unlock:
1496 rcu_read_unlock();
1497
1498 return 0;
1499}
1500EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
1501
1502/*
1503 * Works only for OPP v2 bindings.
1504 *
1505 * cpumask should be already set to mask of cpu_dev->id.
1506 * Returns -ENOENT if operating-points-v2 bindings aren't supported.
1507 */
1508int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
1509{
1510 struct device_node *np, *tmp_np;
1511 struct device *tcpu_dev;
1512 int cpu, ret = 0;
1513
1514 /* Get OPP descriptor node */
1515 np = _of_get_opp_desc_node(cpu_dev);
1516 if (!np) {
1517 dev_dbg(cpu_dev, "%s: Couldn't find opp node: %ld\n", __func__,
1518 PTR_ERR(np));
1519 return -ENOENT;
1520 }
1521
1522 /* OPPs are shared ? */
1523 if (!of_property_read_bool(np, "opp-shared"))
1524 goto put_cpu_node;
1525
1526 for_each_possible_cpu(cpu) {
1527 if (cpu == cpu_dev->id)
1528 continue;
1529
1530 tcpu_dev = get_cpu_device(cpu);
1531 if (!tcpu_dev) {
1532 dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
1533 __func__, cpu);
1534 ret = -ENODEV;
1535 goto put_cpu_node;
1536 }
1537
1538 /* Get OPP descriptor node */
1539 tmp_np = _of_get_opp_desc_node(tcpu_dev);
1540 if (!tmp_np) {
1541 dev_err(tcpu_dev, "%s: Couldn't find opp node: %ld\n",
1542 __func__, PTR_ERR(tmp_np));
1543 ret = PTR_ERR(tmp_np);
1544 goto put_cpu_node;
1545 }
1546
1547 /* CPUs are sharing opp node */
1548 if (np == tmp_np)
1549 cpumask_set_cpu(cpu, cpumask);
1550
1551 of_node_put(tmp_np);
1552 }
1553
1554put_cpu_node:
1555 of_node_put(np);
1556 return ret;
1557}
1558EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
1559#endif 1293#endif
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c
index 0dd033016e9d..3d946b508a13 100644
--- a/drivers/base/power/opp/cpu.c
+++ b/drivers/base/power/opp/cpu.c
@@ -10,17 +10,18 @@
10 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13#include <linux/cpu.h>
13#include <linux/cpufreq.h> 14#include <linux/cpufreq.h>
14#include <linux/device.h>
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/export.h> 17#include <linux/export.h>
18#include <linux/kernel.h> 18#include <linux/of.h>
19#include <linux/pm_opp.h>
20#include <linux/rcupdate.h>
21#include <linux/slab.h> 19#include <linux/slab.h>
22 20
21#include "opp.h"
22
23#ifdef CONFIG_CPU_FREQ 23#ifdef CONFIG_CPU_FREQ
24
24/** 25/**
25 * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device 26 * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
26 * @dev: device for which we do this operation 27 * @dev: device for which we do this operation
@@ -114,3 +115,154 @@ void dev_pm_opp_free_cpufreq_table(struct device *dev,
114} 115}
115EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); 116EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
116#endif /* CONFIG_CPU_FREQ */ 117#endif /* CONFIG_CPU_FREQ */
118
119/* Required only for V1 bindings, as v2 can manage it from DT itself */
120int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
121{
122 struct device_list_opp *list_dev;
123 struct device_opp *dev_opp;
124 struct device *dev;
125 int cpu, ret = 0;
126
127 rcu_read_lock();
128
129 dev_opp = _find_device_opp(cpu_dev);
130 if (IS_ERR(dev_opp)) {
131 ret = -EINVAL;
132 goto out_rcu_read_unlock;
133 }
134
135 for_each_cpu(cpu, cpumask) {
136 if (cpu == cpu_dev->id)
137 continue;
138
139 dev = get_cpu_device(cpu);
140 if (!dev) {
141 dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
142 __func__, cpu);
143 continue;
144 }
145
146 list_dev = _add_list_dev(dev, dev_opp);
147 if (!list_dev) {
148 dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
149 __func__, cpu);
150 continue;
151 }
152 }
153out_rcu_read_unlock:
154 rcu_read_unlock();
155
156 return 0;
157}
158EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
159
160#ifdef CONFIG_OF
161void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask)
162{
163 struct device *cpu_dev;
164 int cpu;
165
166 WARN_ON(cpumask_empty(cpumask));
167
168 for_each_cpu(cpu, cpumask) {
169 cpu_dev = get_cpu_device(cpu);
170 if (!cpu_dev) {
171 pr_err("%s: failed to get cpu%d device\n", __func__,
172 cpu);
173 continue;
174 }
175
176 dev_pm_opp_of_remove_table(cpu_dev);
177 }
178}
179EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
180
181int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask)
182{
183 struct device *cpu_dev;
184 int cpu, ret = 0;
185
186 WARN_ON(cpumask_empty(cpumask));
187
188 for_each_cpu(cpu, cpumask) {
189 cpu_dev = get_cpu_device(cpu);
190 if (!cpu_dev) {
191 pr_err("%s: failed to get cpu%d device\n", __func__,
192 cpu);
193 continue;
194 }
195
196 ret = dev_pm_opp_of_add_table(cpu_dev);
197 if (ret) {
198 pr_err("%s: couldn't find opp table for cpu:%d, %d\n",
199 __func__, cpu, ret);
200
201 /* Free all other OPPs */
202 dev_pm_opp_of_cpumask_remove_table(cpumask);
203 break;
204 }
205 }
206
207 return ret;
208}
209EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
210
211/*
212 * Works only for OPP v2 bindings.
213 *
214 * cpumask should be already set to mask of cpu_dev->id.
215 * Returns -ENOENT if operating-points-v2 bindings aren't supported.
216 */
217int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
218{
219 struct device_node *np, *tmp_np;
220 struct device *tcpu_dev;
221 int cpu, ret = 0;
222
223 /* Get OPP descriptor node */
224 np = _of_get_opp_desc_node(cpu_dev);
225 if (!np) {
226 dev_dbg(cpu_dev, "%s: Couldn't find opp node: %ld\n", __func__,
227 PTR_ERR(np));
228 return -ENOENT;
229 }
230
231 /* OPPs are shared ? */
232 if (!of_property_read_bool(np, "opp-shared"))
233 goto put_cpu_node;
234
235 for_each_possible_cpu(cpu) {
236 if (cpu == cpu_dev->id)
237 continue;
238
239 tcpu_dev = get_cpu_device(cpu);
240 if (!tcpu_dev) {
241 dev_err(cpu_dev, "%s: failed to get cpu%d device\n",
242 __func__, cpu);
243 ret = -ENODEV;
244 goto put_cpu_node;
245 }
246
247 /* Get OPP descriptor node */
248 tmp_np = _of_get_opp_desc_node(tcpu_dev);
249 if (!tmp_np) {
250 dev_err(tcpu_dev, "%s: Couldn't find opp node: %ld\n",
251 __func__, PTR_ERR(tmp_np));
252 ret = PTR_ERR(tmp_np);
253 goto put_cpu_node;
254 }
255
256 /* CPUs are sharing opp node */
257 if (np == tmp_np)
258 cpumask_set_cpu(cpu, cpumask);
259
260 of_node_put(tmp_np);
261 }
262
263put_cpu_node:
264 of_node_put(np);
265 return ret;
266}
267EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
268#endif
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
new file mode 100644
index 000000000000..dcb38f78dae4
--- /dev/null
+++ b/drivers/base/power/opp/opp.h
@@ -0,0 +1,143 @@
1/*
2 * Generic OPP Interface
3 *
4 * Copyright (C) 2009-2010 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
14#ifndef __DRIVER_OPP_H__
15#define __DRIVER_OPP_H__
16
17#include <linux/device.h>
18#include <linux/kernel.h>
19#include <linux/list.h>
20#include <linux/pm_opp.h>
21#include <linux/rculist.h>
22#include <linux/rcupdate.h>
23
24/*
25 * Internal data structure organization with the OPP layer library is as
26 * follows:
27 * dev_opp_list (root)
28 * |- device 1 (represents voltage domain 1)
29 * | |- opp 1 (availability, freq, voltage)
30 * | |- opp 2 ..
31 * ... ...
32 * | `- opp n ..
33 * |- device 2 (represents the next voltage domain)
34 * ...
35 * `- device m (represents mth voltage domain)
36 * device 1, 2.. are represented by dev_opp structure while each opp
37 * is represented by the opp structure.
38 */
39
40/**
41 * struct dev_pm_opp - Generic OPP description structure
42 * @node: opp list node. The nodes are maintained throughout the lifetime
43 * of boot. It is expected only an optimal set of OPPs are
44 * added to the library by the SoC framework.
45 * RCU usage: opp list is traversed with RCU locks. node
46 * modification is possible realtime, hence the modifications
47 * are protected by the dev_opp_list_lock for integrity.
48 * IMPORTANT: the opp nodes should be maintained in increasing
49 * order.
50 * @dynamic: not-created from static DT entries.
51 * @available: true/false - marks if this OPP as available or not
52 * @turbo: true if turbo (boost) OPP
53 * @rate: Frequency in hertz
54 * @u_volt: Target voltage in microvolts corresponding to this OPP
55 * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
56 * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
57 * @u_amp: Maximum current drawn by the device in microamperes
58 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
59 * frequency from any other OPP's frequency.
60 * @dev_opp: points back to the device_opp struct this opp belongs to
61 * @rcu_head: RCU callback head used for deferred freeing
62 * @np: OPP's device node.
63 *
64 * This structure stores the OPP information for a given device.
65 */
66struct dev_pm_opp {
67 struct list_head node;
68
69 bool available;
70 bool dynamic;
71 bool turbo;
72 unsigned long rate;
73
74 unsigned long u_volt;
75 unsigned long u_volt_min;
76 unsigned long u_volt_max;
77 unsigned long u_amp;
78 unsigned long clock_latency_ns;
79
80 struct device_opp *dev_opp;
81 struct rcu_head rcu_head;
82
83 struct device_node *np;
84};
85
86/**
87 * struct device_list_opp - devices managed by 'struct device_opp'
88 * @node: list node
89 * @dev: device to which the struct object belongs
90 * @rcu_head: RCU callback head used for deferred freeing
91 *
92 * This is an internal data structure maintaining the list of devices that are
93 * managed by 'struct device_opp'.
94 */
95struct device_list_opp {
96 struct list_head node;
97 const struct device *dev;
98 struct rcu_head rcu_head;
99};
100
101/**
102 * struct device_opp - Device opp structure
103 * @node: list node - contains the devices with OPPs that
104 * have been registered. Nodes once added are not modified in this
105 * list.
106 * RCU usage: nodes are not modified in the list of device_opp,
107 * however addition is possible and is secured by dev_opp_list_lock
108 * @srcu_head: notifier head to notify the OPP availability changes.
109 * @rcu_head: RCU callback head used for deferred freeing
110 * @dev_list: list of devices that share these OPPs
111 * @opp_list: list of opps
112 * @np: struct device_node pointer for opp's DT node.
113 * @shared_opp: OPP is shared between multiple devices.
114 *
115 * This is an internal data structure maintaining the link to opps attached to
116 * a device. This structure is not meant to be shared to users as it is
117 * meant for book keeping and private to OPP library.
118 *
119 * Because the opp structures can be used from both rcu and srcu readers, we
120 * need to wait for the grace period of both of them before freeing any
121 * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
122 */
123struct device_opp {
124 struct list_head node;
125
126 struct srcu_notifier_head srcu_head;
127 struct rcu_head rcu_head;
128 struct list_head dev_list;
129 struct list_head opp_list;
130
131 struct device_node *np;
132 unsigned long clock_latency_ns_max;
133 bool shared_opp;
134 struct dev_pm_opp *suspend_opp;
135};
136
137/* Routines internal to opp core */
138struct device_opp *_find_device_opp(struct device *dev);
139struct device_list_opp *_add_list_dev(const struct device *dev,
140 struct device_opp *dev_opp);
141struct device_node *_of_get_opp_desc_node(struct device *dev);
142
143#endif /* __DRIVER_OPP_H__ */