diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-11-01 18:54:37 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-11-01 18:54:37 -0500 |
commit | 394f7164e65a734f815543d918c7bdc0587593a6 (patch) | |
tree | 19e57816a0c95a67e5f8cd20276673bc69df0556 | |
parent | dcf3d0183f100a14f60eb5993e124a4a1322ee9a (diff) | |
parent | a6eed752f5fb40990eb28fddb2b93258fb7e3be0 (diff) |
Merge branch 'pm-opp'
* pm-opp:
PM / OPP: passing NULL to PTR_ERR()
PM / OPP: Move cpu specific code to opp/cpu.c
PM / OPP: Move opp core to its own directory
PM / OPP: Prefix exported opp routines with dev_pm_opp_
PM / OPP: Rename opp init/free table routines
PM / OPP: reuse of_parse_phandle()
-rw-r--r-- | arch/arm/mach-imx/mach-imx6q.c | 2 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/opp/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/opp/core.c (renamed from drivers/base/power/opp.c) | 363 | ||||
-rw-r--r-- | drivers/base/power/opp/cpu.c | 267 | ||||
-rw-r--r-- | drivers/base/power/opp/opp.h | 143 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpufreq/arm_big_little.h | 2 | ||||
-rw-r--r-- | drivers/cpufreq/arm_big_little_dt.c | 4 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt.c | 10 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_opp.c | 114 | ||||
-rw-r--r-- | drivers/cpufreq/exynos5440-cpufreq.c | 6 | ||||
-rw-r--r-- | drivers/cpufreq/imx6q-cpufreq.c | 6 | ||||
-rw-r--r-- | drivers/cpufreq/mt8173-cpufreq.c | 6 | ||||
-rw-r--r-- | include/linux/pm_opp.h | 24 |
15 files changed, 473 insertions, 479 deletions
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 9602cc12d2f1..3878494bd118 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c | |||
@@ -350,7 +350,7 @@ static void __init imx6q_opp_init(void) | |||
350 | return; | 350 | return; |
351 | } | 351 | } |
352 | 352 | ||
353 | if (of_init_opp_table(cpu_dev)) { | 353 | if (dev_pm_opp_of_add_table(cpu_dev)) { |
354 | pr_warn("failed to init OPP table\n"); | 354 | pr_warn("failed to init OPP table\n"); |
355 | goto put_node; | 355 | goto put_node; |
356 | } | 356 | } |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index f94a6ccfe787..5998c53280f5 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o | 1 | obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o |
2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o | 2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o |
3 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 3 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
4 | obj-$(CONFIG_PM_OPP) += opp.o | 4 | obj-$(CONFIG_PM_OPP) += opp/ |
5 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o | 5 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o |
6 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o | 6 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o |
7 | 7 | ||
diff --git a/drivers/base/power/opp/Makefile b/drivers/base/power/opp/Makefile new file mode 100644 index 000000000000..33c1e18c41a4 --- /dev/null +++ b/drivers/base/power/opp/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | ||
2 | obj-y += core.o cpu.o | ||
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp/core.c index 7ae7cd990fbf..d5c1149ff123 100644 --- a/drivers/base/power/opp.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 | */ | ||
69 | struct 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 | */ | ||
98 | struct 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 | */ | ||
126 | struct 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 | */ |
203 | static struct device_opp *_find_device_opp(struct device *dev) | 86 | struct 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 | ||
582 | static struct device_list_opp *_add_list_dev(const struct device *dev, | 465 | struct 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 | ||
@@ -828,8 +711,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
828 | * The opp is made available by default and it can be controlled using | 711 | * The opp is made available by default and it can be controlled using |
829 | * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove. | 712 | * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove. |
830 | * | 713 | * |
831 | * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and | 714 | * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table |
832 | * freed by of_free_opp_table. | 715 | * and freed by dev_pm_opp_of_remove_table. |
833 | * | 716 | * |
834 | * Locking: The internal device_opp and opp structures are RCU protected. | 717 | * Locking: The internal device_opp and opp structures are RCU protected. |
835 | * Hence this function internally uses RCU updater strategy with mutex locks | 718 | * Hence this function internally uses RCU updater strategy with mutex locks |
@@ -1220,7 +1103,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); | |||
1220 | 1103 | ||
1221 | #ifdef CONFIG_OF | 1104 | #ifdef CONFIG_OF |
1222 | /** | 1105 | /** |
1223 | * of_free_opp_table() - Free OPP table entries created from static DT entries | 1106 | * dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT |
1107 | * entries | ||
1224 | * @dev: device pointer used to lookup device OPPs. | 1108 | * @dev: device pointer used to lookup device OPPs. |
1225 | * | 1109 | * |
1226 | * Free OPPs created using static entries present in DT. | 1110 | * Free OPPs created using static entries present in DT. |
@@ -1231,7 +1115,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); | |||
1231 | * that this function is *NOT* called under RCU protection or in contexts where | 1115 | * that this function is *NOT* called under RCU protection or in contexts where |
1232 | * mutex cannot be locked. | 1116 | * mutex cannot be locked. |
1233 | */ | 1117 | */ |
1234 | void of_free_opp_table(struct device *dev) | 1118 | void dev_pm_opp_of_remove_table(struct device *dev) |
1235 | { | 1119 | { |
1236 | struct device_opp *dev_opp; | 1120 | struct device_opp *dev_opp; |
1237 | struct dev_pm_opp *opp, *tmp; | 1121 | struct dev_pm_opp *opp, *tmp; |
@@ -1266,91 +1150,34 @@ void of_free_opp_table(struct device *dev) | |||
1266 | unlock: | 1150 | unlock: |
1267 | mutex_unlock(&dev_opp_list_lock); | 1151 | mutex_unlock(&dev_opp_list_lock); |
1268 | } | 1152 | } |
1269 | EXPORT_SYMBOL_GPL(of_free_opp_table); | 1153 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); |
1270 | 1154 | ||
1271 | void of_cpumask_free_opp_table(cpumask_var_t cpumask) | 1155 | /* Returns opp descriptor node for a device, caller must do of_node_put() */ |
1156 | struct device_node *_of_get_opp_desc_node(struct device *dev) | ||
1272 | { | 1157 | { |
1273 | struct device *cpu_dev; | ||
1274 | int cpu; | ||
1275 | |||
1276 | WARN_ON(cpumask_empty(cpumask)); | ||
1277 | |||
1278 | for_each_cpu(cpu, cpumask) { | ||
1279 | cpu_dev = get_cpu_device(cpu); | ||
1280 | if (!cpu_dev) { | ||
1281 | pr_err("%s: failed to get cpu%d device\n", __func__, | ||
1282 | cpu); | ||
1283 | continue; | ||
1284 | } | ||
1285 | |||
1286 | of_free_opp_table(cpu_dev); | ||
1287 | } | ||
1288 | } | ||
1289 | EXPORT_SYMBOL_GPL(of_cpumask_free_opp_table); | ||
1290 | |||
1291 | /* Returns opp descriptor node from its phandle. Caller must do of_node_put() */ | ||
1292 | static struct device_node * | ||
1293 | _of_get_opp_desc_node_from_prop(struct device *dev, const struct property *prop) | ||
1294 | { | ||
1295 | struct device_node *opp_np; | ||
1296 | |||
1297 | opp_np = of_find_node_by_phandle(be32_to_cpup(prop->value)); | ||
1298 | if (!opp_np) { | ||
1299 | dev_err(dev, "%s: Prop: %s contains invalid opp desc phandle\n", | ||
1300 | __func__, prop->name); | ||
1301 | return ERR_PTR(-EINVAL); | ||
1302 | } | ||
1303 | |||
1304 | return opp_np; | ||
1305 | } | ||
1306 | |||
1307 | /* Returns opp descriptor node for a device. Caller must do of_node_put() */ | ||
1308 | static struct device_node *_of_get_opp_desc_node(struct device *dev) | ||
1309 | { | ||
1310 | const struct property *prop; | ||
1311 | |||
1312 | prop = of_find_property(dev->of_node, "operating-points-v2", NULL); | ||
1313 | if (!prop) | ||
1314 | return ERR_PTR(-ENODEV); | ||
1315 | if (!prop->value) | ||
1316 | return ERR_PTR(-ENODATA); | ||
1317 | |||
1318 | /* | 1158 | /* |
1319 | * TODO: Support for multiple OPP tables. | 1159 | * TODO: Support for multiple OPP tables. |
1320 | * | 1160 | * |
1321 | * There should be only ONE phandle present in "operating-points-v2" | 1161 | * There should be only ONE phandle present in "operating-points-v2" |
1322 | * property. | 1162 | * property. |
1323 | */ | 1163 | */ |
1324 | if (prop->length != sizeof(__be32)) { | ||
1325 | dev_err(dev, "%s: Invalid opp desc phandle\n", __func__); | ||
1326 | return ERR_PTR(-EINVAL); | ||
1327 | } | ||
1328 | 1164 | ||
1329 | return _of_get_opp_desc_node_from_prop(dev, prop); | 1165 | return of_parse_phandle(dev->of_node, "operating-points-v2", 0); |
1330 | } | 1166 | } |
1331 | 1167 | ||
1332 | /* Initializes OPP tables based on new bindings */ | 1168 | /* Initializes OPP tables based on new bindings */ |
1333 | static int _of_init_opp_table_v2(struct device *dev, | 1169 | static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) |
1334 | const struct property *prop) | ||
1335 | { | 1170 | { |
1336 | struct device_node *opp_np, *np; | 1171 | struct device_node *np; |
1337 | struct device_opp *dev_opp; | 1172 | struct device_opp *dev_opp; |
1338 | int ret = 0, count = 0; | 1173 | int ret = 0, count = 0; |
1339 | 1174 | ||
1340 | if (!prop->value) | ||
1341 | return -ENODATA; | ||
1342 | |||
1343 | /* Get opp node */ | ||
1344 | opp_np = _of_get_opp_desc_node_from_prop(dev, prop); | ||
1345 | if (IS_ERR(opp_np)) | ||
1346 | return PTR_ERR(opp_np); | ||
1347 | |||
1348 | dev_opp = _managed_opp(opp_np); | 1175 | dev_opp = _managed_opp(opp_np); |
1349 | if (dev_opp) { | 1176 | if (dev_opp) { |
1350 | /* OPPs are already managed */ | 1177 | /* OPPs are already managed */ |
1351 | if (!_add_list_dev(dev, dev_opp)) | 1178 | if (!_add_list_dev(dev, dev_opp)) |
1352 | ret = -ENOMEM; | 1179 | ret = -ENOMEM; |
1353 | goto put_opp_np; | 1180 | return ret; |
1354 | } | 1181 | } |
1355 | 1182 | ||
1356 | /* We have opp-list node now, iterate over it and add OPPs */ | 1183 | /* We have opp-list node now, iterate over it and add OPPs */ |
@@ -1366,10 +1193,8 @@ static int _of_init_opp_table_v2(struct device *dev, | |||
1366 | } | 1193 | } |
1367 | 1194 | ||
1368 | /* There should be one of more OPP defined */ | 1195 | /* There should be one of more OPP defined */ |
1369 | if (WARN_ON(!count)) { | 1196 | if (WARN_ON(!count)) |
1370 | ret = -ENOENT; | 1197 | return -ENOENT; |
1371 | goto put_opp_np; | ||
1372 | } | ||
1373 | 1198 | ||
1374 | dev_opp = _find_device_opp(dev); | 1199 | dev_opp = _find_device_opp(dev); |
1375 | if (WARN_ON(IS_ERR(dev_opp))) { | 1200 | if (WARN_ON(IS_ERR(dev_opp))) { |
@@ -1380,19 +1205,16 @@ static int _of_init_opp_table_v2(struct device *dev, | |||
1380 | dev_opp->np = opp_np; | 1205 | dev_opp->np = opp_np; |
1381 | dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared"); | 1206 | dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared"); |
1382 | 1207 | ||
1383 | of_node_put(opp_np); | ||
1384 | return 0; | 1208 | return 0; |
1385 | 1209 | ||
1386 | free_table: | 1210 | free_table: |
1387 | of_free_opp_table(dev); | 1211 | dev_pm_opp_of_remove_table(dev); |
1388 | put_opp_np: | ||
1389 | of_node_put(opp_np); | ||
1390 | 1212 | ||
1391 | return ret; | 1213 | return ret; |
1392 | } | 1214 | } |
1393 | 1215 | ||
1394 | /* Initializes OPP tables based on old-deprecated bindings */ | 1216 | /* Initializes OPP tables based on old-deprecated bindings */ |
1395 | static int _of_init_opp_table_v1(struct device *dev) | 1217 | static int _of_add_opp_table_v1(struct device *dev) |
1396 | { | 1218 | { |
1397 | const struct property *prop; | 1219 | const struct property *prop; |
1398 | const __be32 *val; | 1220 | const __be32 *val; |
@@ -1429,7 +1251,7 @@ static int _of_init_opp_table_v1(struct device *dev) | |||
1429 | } | 1251 | } |
1430 | 1252 | ||
1431 | /** | 1253 | /** |
1432 | * of_init_opp_table() - Initialize opp table from device tree | 1254 | * dev_pm_opp_of_add_table() - Initialize opp table from device tree |
1433 | * @dev: device pointer used to lookup device OPPs. | 1255 | * @dev: device pointer used to lookup device OPPs. |
1434 | * | 1256 | * |
1435 | * Register the initial OPP table with the OPP library for given device. | 1257 | * Register the initial OPP table with the OPP library for given device. |
@@ -1451,153 +1273,28 @@ static int _of_init_opp_table_v1(struct device *dev) | |||
1451 | * -ENODATA when empty 'operating-points' property is found | 1273 | * -ENODATA when empty 'operating-points' property is found |
1452 | * -EINVAL when invalid entries are found in opp-v2 table | 1274 | * -EINVAL when invalid entries are found in opp-v2 table |
1453 | */ | 1275 | */ |
1454 | int of_init_opp_table(struct device *dev) | 1276 | int dev_pm_opp_of_add_table(struct device *dev) |
1455 | { | 1277 | { |
1456 | const struct property *prop; | 1278 | struct device_node *opp_np; |
1279 | int ret; | ||
1457 | 1280 | ||
1458 | /* | 1281 | /* |
1459 | * OPPs have two version of bindings now. The older one is deprecated, | 1282 | * OPPs have two version of bindings now. The older one is deprecated, |
1460 | * try for the new binding first. | 1283 | * try for the new binding first. |
1461 | */ | 1284 | */ |
1462 | prop = of_find_property(dev->of_node, "operating-points-v2", NULL); | 1285 | opp_np = _of_get_opp_desc_node(dev); |
1463 | if (!prop) { | 1286 | if (!opp_np) { |
1464 | /* | 1287 | /* |
1465 | * Try old-deprecated bindings for backward compatibility with | 1288 | * Try old-deprecated bindings for backward compatibility with |
1466 | * older dtbs. | 1289 | * older dtbs. |
1467 | */ | 1290 | */ |
1468 | return _of_init_opp_table_v1(dev); | 1291 | return _of_add_opp_table_v1(dev); |
1469 | } | ||
1470 | |||
1471 | return _of_init_opp_table_v2(dev, prop); | ||
1472 | } | ||
1473 | EXPORT_SYMBOL_GPL(of_init_opp_table); | ||
1474 | |||
1475 | int of_cpumask_init_opp_table(cpumask_var_t cpumask) | ||
1476 | { | ||
1477 | struct device *cpu_dev; | ||
1478 | int cpu, ret = 0; | ||
1479 | |||
1480 | WARN_ON(cpumask_empty(cpumask)); | ||
1481 | |||
1482 | for_each_cpu(cpu, cpumask) { | ||
1483 | cpu_dev = get_cpu_device(cpu); | ||
1484 | if (!cpu_dev) { | ||
1485 | pr_err("%s: failed to get cpu%d device\n", __func__, | ||
1486 | cpu); | ||
1487 | continue; | ||
1488 | } | ||
1489 | |||
1490 | ret = of_init_opp_table(cpu_dev); | ||
1491 | if (ret) { | ||
1492 | pr_err("%s: couldn't find opp table for cpu:%d, %d\n", | ||
1493 | __func__, cpu, ret); | ||
1494 | |||
1495 | /* Free all other OPPs */ | ||
1496 | of_cpumask_free_opp_table(cpumask); | ||
1497 | break; | ||
1498 | } | ||
1499 | } | 1292 | } |
1500 | 1293 | ||
1501 | return ret; | 1294 | ret = _of_add_opp_table_v2(dev, opp_np); |
1502 | } | 1295 | of_node_put(opp_np); |
1503 | EXPORT_SYMBOL_GPL(of_cpumask_init_opp_table); | ||
1504 | |||
1505 | /* Required only for V1 bindings, as v2 can manage it from DT itself */ | ||
1506 | int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) | ||
1507 | { | ||
1508 | struct device_list_opp *list_dev; | ||
1509 | struct device_opp *dev_opp; | ||
1510 | struct device *dev; | ||
1511 | int cpu, ret = 0; | ||
1512 | |||
1513 | rcu_read_lock(); | ||
1514 | |||
1515 | dev_opp = _find_device_opp(cpu_dev); | ||
1516 | if (IS_ERR(dev_opp)) { | ||
1517 | ret = -EINVAL; | ||
1518 | goto out_rcu_read_unlock; | ||
1519 | } | ||
1520 | |||
1521 | for_each_cpu(cpu, cpumask) { | ||
1522 | if (cpu == cpu_dev->id) | ||
1523 | continue; | ||
1524 | |||
1525 | dev = get_cpu_device(cpu); | ||
1526 | if (!dev) { | ||
1527 | dev_err(cpu_dev, "%s: failed to get cpu%d device\n", | ||
1528 | __func__, cpu); | ||
1529 | continue; | ||
1530 | } | ||
1531 | |||
1532 | list_dev = _add_list_dev(dev, dev_opp); | ||
1533 | if (!list_dev) { | ||
1534 | dev_err(dev, "%s: failed to add list-dev for cpu%d device\n", | ||
1535 | __func__, cpu); | ||
1536 | continue; | ||
1537 | } | ||
1538 | } | ||
1539 | out_rcu_read_unlock: | ||
1540 | rcu_read_unlock(); | ||
1541 | |||
1542 | return 0; | ||
1543 | } | ||
1544 | EXPORT_SYMBOL_GPL(set_cpus_sharing_opps); | ||
1545 | |||
1546 | /* | ||
1547 | * Works only for OPP v2 bindings. | ||
1548 | * | ||
1549 | * cpumask should be already set to mask of cpu_dev->id. | ||
1550 | * Returns -ENOENT if operating-points-v2 bindings aren't supported. | ||
1551 | */ | ||
1552 | int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) | ||
1553 | { | ||
1554 | struct device_node *np, *tmp_np; | ||
1555 | struct device *tcpu_dev; | ||
1556 | int cpu, ret = 0; | ||
1557 | |||
1558 | /* Get OPP descriptor node */ | ||
1559 | np = _of_get_opp_desc_node(cpu_dev); | ||
1560 | if (IS_ERR(np)) { | ||
1561 | dev_dbg(cpu_dev, "%s: Couldn't find opp node: %ld\n", __func__, | ||
1562 | PTR_ERR(np)); | ||
1563 | return -ENOENT; | ||
1564 | } | ||
1565 | |||
1566 | /* OPPs are shared ? */ | ||
1567 | if (!of_property_read_bool(np, "opp-shared")) | ||
1568 | goto put_cpu_node; | ||
1569 | |||
1570 | for_each_possible_cpu(cpu) { | ||
1571 | if (cpu == cpu_dev->id) | ||
1572 | continue; | ||
1573 | |||
1574 | tcpu_dev = get_cpu_device(cpu); | ||
1575 | if (!tcpu_dev) { | ||
1576 | dev_err(cpu_dev, "%s: failed to get cpu%d device\n", | ||
1577 | __func__, cpu); | ||
1578 | ret = -ENODEV; | ||
1579 | goto put_cpu_node; | ||
1580 | } | ||
1581 | |||
1582 | /* Get OPP descriptor node */ | ||
1583 | tmp_np = _of_get_opp_desc_node(tcpu_dev); | ||
1584 | if (IS_ERR(tmp_np)) { | ||
1585 | dev_err(tcpu_dev, "%s: Couldn't find opp node: %ld\n", | ||
1586 | __func__, PTR_ERR(tmp_np)); | ||
1587 | ret = PTR_ERR(tmp_np); | ||
1588 | goto put_cpu_node; | ||
1589 | } | ||
1590 | |||
1591 | /* CPUs are sharing opp node */ | ||
1592 | if (np == tmp_np) | ||
1593 | cpumask_set_cpu(cpu, cpumask); | ||
1594 | |||
1595 | of_node_put(tmp_np); | ||
1596 | } | ||
1597 | 1296 | ||
1598 | put_cpu_node: | ||
1599 | of_node_put(np); | ||
1600 | return ret; | 1297 | return ret; |
1601 | } | 1298 | } |
1602 | EXPORT_SYMBOL_GPL(of_get_cpus_sharing_opps); | 1299 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); |
1603 | #endif | 1300 | #endif |
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c new file mode 100644 index 000000000000..7654c5606307 --- /dev/null +++ b/drivers/base/power/opp/cpu.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * Generic OPP helper interface for CPU device | ||
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/cpu.h> | ||
14 | #include <linux/cpufreq.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/export.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include "opp.h" | ||
22 | |||
23 | #ifdef CONFIG_CPU_FREQ | ||
24 | |||
25 | /** | ||
26 | * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device | ||
27 | * @dev: device for which we do this operation | ||
28 | * @table: Cpufreq table returned back to caller | ||
29 | * | ||
30 | * Generate a cpufreq table for a provided device- this assumes that the | ||
31 | * opp list is already initialized and ready for usage. | ||
32 | * | ||
33 | * This function allocates required memory for the cpufreq table. It is | ||
34 | * expected that the caller does the required maintenance such as freeing | ||
35 | * the table as required. | ||
36 | * | ||
37 | * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM | ||
38 | * if no memory available for the operation (table is not populated), returns 0 | ||
39 | * if successful and table is populated. | ||
40 | * | ||
41 | * WARNING: It is important for the callers to ensure refreshing their copy of | ||
42 | * the table if any of the mentioned functions have been invoked in the interim. | ||
43 | * | ||
44 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
45 | * Since we just use the regular accessor functions to access the internal data | ||
46 | * structures, we use RCU read lock inside this function. As a result, users of | ||
47 | * this function DONOT need to use explicit locks for invoking. | ||
48 | */ | ||
49 | int dev_pm_opp_init_cpufreq_table(struct device *dev, | ||
50 | struct cpufreq_frequency_table **table) | ||
51 | { | ||
52 | struct dev_pm_opp *opp; | ||
53 | struct cpufreq_frequency_table *freq_table = NULL; | ||
54 | int i, max_opps, ret = 0; | ||
55 | unsigned long rate; | ||
56 | |||
57 | rcu_read_lock(); | ||
58 | |||
59 | max_opps = dev_pm_opp_get_opp_count(dev); | ||
60 | if (max_opps <= 0) { | ||
61 | ret = max_opps ? max_opps : -ENODATA; | ||
62 | goto out; | ||
63 | } | ||
64 | |||
65 | freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); | ||
66 | if (!freq_table) { | ||
67 | ret = -ENOMEM; | ||
68 | goto out; | ||
69 | } | ||
70 | |||
71 | for (i = 0, rate = 0; i < max_opps; i++, rate++) { | ||
72 | /* find next rate */ | ||
73 | opp = dev_pm_opp_find_freq_ceil(dev, &rate); | ||
74 | if (IS_ERR(opp)) { | ||
75 | ret = PTR_ERR(opp); | ||
76 | goto out; | ||
77 | } | ||
78 | freq_table[i].driver_data = i; | ||
79 | freq_table[i].frequency = rate / 1000; | ||
80 | |||
81 | /* Is Boost/turbo opp ? */ | ||
82 | if (dev_pm_opp_is_turbo(opp)) | ||
83 | freq_table[i].flags = CPUFREQ_BOOST_FREQ; | ||
84 | } | ||
85 | |||
86 | freq_table[i].driver_data = i; | ||
87 | freq_table[i].frequency = CPUFREQ_TABLE_END; | ||
88 | |||
89 | *table = &freq_table[0]; | ||
90 | |||
91 | out: | ||
92 | rcu_read_unlock(); | ||
93 | if (ret) | ||
94 | kfree(freq_table); | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table); | ||
99 | |||
100 | /** | ||
101 | * dev_pm_opp_free_cpufreq_table() - free the cpufreq table | ||
102 | * @dev: device for which we do this operation | ||
103 | * @table: table to free | ||
104 | * | ||
105 | * Free up the table allocated by dev_pm_opp_init_cpufreq_table | ||
106 | */ | ||
107 | void dev_pm_opp_free_cpufreq_table(struct device *dev, | ||
108 | struct cpufreq_frequency_table **table) | ||
109 | { | ||
110 | if (!table) | ||
111 | return; | ||
112 | |||
113 | kfree(*table); | ||
114 | *table = NULL; | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); | ||
117 | #endif /* CONFIG_CPU_FREQ */ | ||
118 | |||
119 | /* Required only for V1 bindings, as v2 can manage it from DT itself */ | ||
120 | int 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 | } | ||
153 | out_rcu_read_unlock: | ||
154 | rcu_read_unlock(); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus); | ||
159 | |||
160 | #ifdef CONFIG_OF | ||
161 | void 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 | } | ||
179 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); | ||
180 | |||
181 | int 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 | } | ||
209 | EXPORT_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 | */ | ||
217 | int 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 cpu_dev node.\n", __func__); | ||
227 | return -ENOENT; | ||
228 | } | ||
229 | |||
230 | /* OPPs are shared ? */ | ||
231 | if (!of_property_read_bool(np, "opp-shared")) | ||
232 | goto put_cpu_node; | ||
233 | |||
234 | for_each_possible_cpu(cpu) { | ||
235 | if (cpu == cpu_dev->id) | ||
236 | continue; | ||
237 | |||
238 | tcpu_dev = get_cpu_device(cpu); | ||
239 | if (!tcpu_dev) { | ||
240 | dev_err(cpu_dev, "%s: failed to get cpu%d device\n", | ||
241 | __func__, cpu); | ||
242 | ret = -ENODEV; | ||
243 | goto put_cpu_node; | ||
244 | } | ||
245 | |||
246 | /* Get OPP descriptor node */ | ||
247 | tmp_np = _of_get_opp_desc_node(tcpu_dev); | ||
248 | if (!tmp_np) { | ||
249 | dev_err(tcpu_dev, "%s: Couldn't find tcpu_dev node.\n", | ||
250 | __func__); | ||
251 | ret = -ENOENT; | ||
252 | goto put_cpu_node; | ||
253 | } | ||
254 | |||
255 | /* CPUs are sharing opp node */ | ||
256 | if (np == tmp_np) | ||
257 | cpumask_set_cpu(cpu, cpumask); | ||
258 | |||
259 | of_node_put(tmp_np); | ||
260 | } | ||
261 | |||
262 | put_cpu_node: | ||
263 | of_node_put(np); | ||
264 | return ret; | ||
265 | } | ||
266 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus); | ||
267 | #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 | */ | ||
66 | struct 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 | */ | ||
95 | struct 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 | */ | ||
123 | struct 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 */ | ||
138 | struct device_opp *_find_device_opp(struct device *dev); | ||
139 | struct device_list_opp *_add_list_dev(const struct device *dev, | ||
140 | struct device_opp *dev_opp); | ||
141 | struct device_node *_of_get_opp_desc_node(struct device *dev); | ||
142 | |||
143 | #endif /* __DRIVER_OPP_H__ */ | ||
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 47a7ebbcf998..d11309c487d0 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | # CPUfreq core | 1 | # CPUfreq core |
2 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o | 2 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o |
3 | obj-$(CONFIG_PM_OPP) += cpufreq_opp.o | ||
4 | 3 | ||
5 | # CPUfreq stats | 4 | # CPUfreq stats |
6 | obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o | 5 | obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o |
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h index a211f7db9d32..b88889d9387e 100644 --- a/drivers/cpufreq/arm_big_little.h +++ b/drivers/cpufreq/arm_big_little.h | |||
@@ -28,7 +28,7 @@ struct cpufreq_arm_bL_ops { | |||
28 | 28 | ||
29 | /* | 29 | /* |
30 | * This must set opp table for cpu_dev in a similar way as done by | 30 | * This must set opp table for cpu_dev in a similar way as done by |
31 | * of_init_opp_table(). | 31 | * dev_pm_opp_of_add_table(). |
32 | */ | 32 | */ |
33 | int (*init_opp_table)(struct device *cpu_dev); | 33 | int (*init_opp_table)(struct device *cpu_dev); |
34 | 34 | ||
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c index 36d91dba2965..16ddeefe9443 100644 --- a/drivers/cpufreq/arm_big_little_dt.c +++ b/drivers/cpufreq/arm_big_little_dt.c | |||
@@ -54,7 +54,7 @@ static int dt_init_opp_table(struct device *cpu_dev) | |||
54 | return -ENOENT; | 54 | return -ENOENT; |
55 | } | 55 | } |
56 | 56 | ||
57 | ret = of_init_opp_table(cpu_dev); | 57 | ret = dev_pm_opp_of_add_table(cpu_dev); |
58 | of_node_put(np); | 58 | of_node_put(np); |
59 | 59 | ||
60 | return ret; | 60 | return ret; |
@@ -82,7 +82,7 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = { | |||
82 | .name = "dt-bl", | 82 | .name = "dt-bl", |
83 | .get_transition_latency = dt_get_transition_latency, | 83 | .get_transition_latency = dt_get_transition_latency, |
84 | .init_opp_table = dt_init_opp_table, | 84 | .init_opp_table = dt_init_opp_table, |
85 | .free_opp_table = of_free_opp_table, | 85 | .free_opp_table = dev_pm_opp_of_remove_table, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static int generic_bL_probe(struct platform_device *pdev) | 88 | static int generic_bL_probe(struct platform_device *pdev) |
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 7c0d70e2a861..90d64081ddb3 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c | |||
@@ -216,7 +216,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) | |||
216 | } | 216 | } |
217 | 217 | ||
218 | /* Get OPP-sharing information from "operating-points-v2" bindings */ | 218 | /* Get OPP-sharing information from "operating-points-v2" bindings */ |
219 | ret = of_get_cpus_sharing_opps(cpu_dev, policy->cpus); | 219 | ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); |
220 | if (ret) { | 220 | if (ret) { |
221 | /* | 221 | /* |
222 | * operating-points-v2 not supported, fallback to old method of | 222 | * operating-points-v2 not supported, fallback to old method of |
@@ -238,7 +238,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) | |||
238 | * | 238 | * |
239 | * OPPs might be populated at runtime, don't check for error here | 239 | * OPPs might be populated at runtime, don't check for error here |
240 | */ | 240 | */ |
241 | of_cpumask_init_opp_table(policy->cpus); | 241 | dev_pm_opp_of_cpumask_add_table(policy->cpus); |
242 | 242 | ||
243 | /* | 243 | /* |
244 | * But we need OPP table to function so if it is not there let's | 244 | * But we need OPP table to function so if it is not there let's |
@@ -261,7 +261,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) | |||
261 | * OPP tables are initialized only for policy->cpu, do it for | 261 | * OPP tables are initialized only for policy->cpu, do it for |
262 | * others as well. | 262 | * others as well. |
263 | */ | 263 | */ |
264 | ret = set_cpus_sharing_opps(cpu_dev, policy->cpus); | 264 | ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); |
265 | if (ret) | 265 | if (ret) |
266 | dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", | 266 | dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", |
267 | __func__, ret); | 267 | __func__, ret); |
@@ -368,7 +368,7 @@ out_free_cpufreq_table: | |||
368 | out_free_priv: | 368 | out_free_priv: |
369 | kfree(priv); | 369 | kfree(priv); |
370 | out_free_opp: | 370 | out_free_opp: |
371 | of_cpumask_free_opp_table(policy->cpus); | 371 | dev_pm_opp_of_cpumask_remove_table(policy->cpus); |
372 | out_node_put: | 372 | out_node_put: |
373 | of_node_put(np); | 373 | of_node_put(np); |
374 | out_put_reg_clk: | 374 | out_put_reg_clk: |
@@ -385,7 +385,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) | |||
385 | 385 | ||
386 | cpufreq_cooling_unregister(priv->cdev); | 386 | cpufreq_cooling_unregister(priv->cdev); |
387 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); | 387 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); |
388 | of_cpumask_free_opp_table(policy->related_cpus); | 388 | dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); |
389 | clk_put(policy->clk); | 389 | clk_put(policy->clk); |
390 | if (!IS_ERR(priv->cpu_reg)) | 390 | if (!IS_ERR(priv->cpu_reg)) |
391 | regulator_put(priv->cpu_reg); | 391 | regulator_put(priv->cpu_reg); |
diff --git a/drivers/cpufreq/cpufreq_opp.c b/drivers/cpufreq/cpufreq_opp.c deleted file mode 100644 index 0f5e6d5f6da0..000000000000 --- a/drivers/cpufreq/cpufreq_opp.c +++ /dev/null | |||
@@ -1,114 +0,0 @@ | |||
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 = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); | ||
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 | /* Is Boost/turbo opp ? */ | ||
80 | if (dev_pm_opp_is_turbo(opp)) | ||
81 | freq_table[i].flags = CPUFREQ_BOOST_FREQ; | ||
82 | } | ||
83 | |||
84 | freq_table[i].driver_data = i; | ||
85 | freq_table[i].frequency = CPUFREQ_TABLE_END; | ||
86 | |||
87 | *table = &freq_table[0]; | ||
88 | |||
89 | out: | ||
90 | rcu_read_unlock(); | ||
91 | if (ret) | ||
92 | kfree(freq_table); | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table); | ||
97 | |||
98 | /** | ||
99 | * dev_pm_opp_free_cpufreq_table() - free the cpufreq table | ||
100 | * @dev: device for which we do this operation | ||
101 | * @table: table to free | ||
102 | * | ||
103 | * Free up the table allocated by dev_pm_opp_init_cpufreq_table | ||
104 | */ | ||
105 | void dev_pm_opp_free_cpufreq_table(struct device *dev, | ||
106 | struct cpufreq_frequency_table **table) | ||
107 | { | ||
108 | if (!table) | ||
109 | return; | ||
110 | |||
111 | kfree(*table); | ||
112 | *table = NULL; | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); | ||
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index 21a90ed7f3d8..c0f3373706f4 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c | |||
@@ -360,7 +360,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) | |||
360 | goto err_put_node; | 360 | goto err_put_node; |
361 | } | 361 | } |
362 | 362 | ||
363 | ret = of_init_opp_table(dvfs_info->dev); | 363 | ret = dev_pm_opp_of_add_table(dvfs_info->dev); |
364 | if (ret) { | 364 | if (ret) { |
365 | dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret); | 365 | dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret); |
366 | goto err_put_node; | 366 | goto err_put_node; |
@@ -424,7 +424,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) | |||
424 | err_free_table: | 424 | err_free_table: |
425 | dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); | 425 | dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); |
426 | err_free_opp: | 426 | err_free_opp: |
427 | of_free_opp_table(dvfs_info->dev); | 427 | dev_pm_opp_of_remove_table(dvfs_info->dev); |
428 | err_put_node: | 428 | err_put_node: |
429 | of_node_put(np); | 429 | of_node_put(np); |
430 | dev_err(&pdev->dev, "%s: failed initialization\n", __func__); | 430 | dev_err(&pdev->dev, "%s: failed initialization\n", __func__); |
@@ -435,7 +435,7 @@ static int exynos_cpufreq_remove(struct platform_device *pdev) | |||
435 | { | 435 | { |
436 | cpufreq_unregister_driver(&exynos_driver); | 436 | cpufreq_unregister_driver(&exynos_driver); |
437 | dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); | 437 | dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); |
438 | of_free_opp_table(dvfs_info->dev); | 438 | dev_pm_opp_of_remove_table(dvfs_info->dev); |
439 | return 0; | 439 | return 0; |
440 | } | 440 | } |
441 | 441 | ||
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 9b4a7bd04dea..ef1fa8145419 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c | |||
@@ -236,7 +236,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) | |||
236 | */ | 236 | */ |
237 | num = dev_pm_opp_get_opp_count(cpu_dev); | 237 | num = dev_pm_opp_get_opp_count(cpu_dev); |
238 | if (num < 0) { | 238 | if (num < 0) { |
239 | ret = of_init_opp_table(cpu_dev); | 239 | ret = dev_pm_opp_of_add_table(cpu_dev); |
240 | if (ret < 0) { | 240 | if (ret < 0) { |
241 | dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); | 241 | dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); |
242 | goto put_reg; | 242 | goto put_reg; |
@@ -346,7 +346,7 @@ free_freq_table: | |||
346 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); | 346 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
347 | out_free_opp: | 347 | out_free_opp: |
348 | if (free_opp) | 348 | if (free_opp) |
349 | of_free_opp_table(cpu_dev); | 349 | dev_pm_opp_of_remove_table(cpu_dev); |
350 | put_reg: | 350 | put_reg: |
351 | if (!IS_ERR(arm_reg)) | 351 | if (!IS_ERR(arm_reg)) |
352 | regulator_put(arm_reg); | 352 | regulator_put(arm_reg); |
@@ -378,7 +378,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev) | |||
378 | cpufreq_unregister_driver(&imx6q_cpufreq_driver); | 378 | cpufreq_unregister_driver(&imx6q_cpufreq_driver); |
379 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); | 379 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
380 | if (free_opp) | 380 | if (free_opp) |
381 | of_free_opp_table(cpu_dev); | 381 | dev_pm_opp_of_remove_table(cpu_dev); |
382 | regulator_put(arm_reg); | 382 | regulator_put(arm_reg); |
383 | if (!IS_ERR(pu_reg)) | 383 | if (!IS_ERR(pu_reg)) |
384 | regulator_put(pu_reg); | 384 | regulator_put(pu_reg); |
diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 49caed293a3b..83001dc5b646 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c | |||
@@ -344,7 +344,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) | |||
344 | /* Both presence and absence of sram regulator are valid cases. */ | 344 | /* Both presence and absence of sram regulator are valid cases. */ |
345 | sram_reg = regulator_get_exclusive(cpu_dev, "sram"); | 345 | sram_reg = regulator_get_exclusive(cpu_dev, "sram"); |
346 | 346 | ||
347 | ret = of_init_opp_table(cpu_dev); | 347 | ret = dev_pm_opp_of_add_table(cpu_dev); |
348 | if (ret) { | 348 | if (ret) { |
349 | pr_warn("no OPP table for cpu%d\n", cpu); | 349 | pr_warn("no OPP table for cpu%d\n", cpu); |
350 | goto out_free_resources; | 350 | goto out_free_resources; |
@@ -378,7 +378,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) | |||
378 | return 0; | 378 | return 0; |
379 | 379 | ||
380 | out_free_opp_table: | 380 | out_free_opp_table: |
381 | of_free_opp_table(cpu_dev); | 381 | dev_pm_opp_of_remove_table(cpu_dev); |
382 | 382 | ||
383 | out_free_resources: | 383 | out_free_resources: |
384 | if (!IS_ERR(proc_reg)) | 384 | if (!IS_ERR(proc_reg)) |
@@ -404,7 +404,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) | |||
404 | if (!IS_ERR(info->inter_clk)) | 404 | if (!IS_ERR(info->inter_clk)) |
405 | clk_put(info->inter_clk); | 405 | clk_put(info->inter_clk); |
406 | 406 | ||
407 | of_free_opp_table(info->cpu_dev); | 407 | dev_pm_opp_of_remove_table(info->cpu_dev); |
408 | } | 408 | } |
409 | 409 | ||
410 | static int mtk_cpufreq_init(struct cpufreq_policy *policy) | 410 | static int mtk_cpufreq_init(struct cpufreq_policy *policy) |
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index e817722ee3f0..9a2e50337af9 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h | |||
@@ -132,37 +132,37 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( | |||
132 | #endif /* CONFIG_PM_OPP */ | 132 | #endif /* CONFIG_PM_OPP */ |
133 | 133 | ||
134 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) | 134 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) |
135 | int of_init_opp_table(struct device *dev); | 135 | int dev_pm_opp_of_add_table(struct device *dev); |
136 | void of_free_opp_table(struct device *dev); | 136 | void dev_pm_opp_of_remove_table(struct device *dev); |
137 | int of_cpumask_init_opp_table(cpumask_var_t cpumask); | 137 | int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask); |
138 | void of_cpumask_free_opp_table(cpumask_var_t cpumask); | 138 | void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask); |
139 | int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask); | 139 | int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask); |
140 | int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask); | 140 | int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask); |
141 | #else | 141 | #else |
142 | static inline int of_init_opp_table(struct device *dev) | 142 | static inline int dev_pm_opp_of_add_table(struct device *dev) |
143 | { | 143 | { |
144 | return -EINVAL; | 144 | return -EINVAL; |
145 | } | 145 | } |
146 | 146 | ||
147 | static inline void of_free_opp_table(struct device *dev) | 147 | static inline void dev_pm_opp_of_remove_table(struct device *dev) |
148 | { | 148 | { |
149 | } | 149 | } |
150 | 150 | ||
151 | static inline int of_cpumask_init_opp_table(cpumask_var_t cpumask) | 151 | static inline int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask) |
152 | { | 152 | { |
153 | return -ENOSYS; | 153 | return -ENOSYS; |
154 | } | 154 | } |
155 | 155 | ||
156 | static inline void of_cpumask_free_opp_table(cpumask_var_t cpumask) | 156 | static inline void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask) |
157 | { | 157 | { |
158 | } | 158 | } |
159 | 159 | ||
160 | static inline int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) | 160 | static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) |
161 | { | 161 | { |
162 | return -ENOSYS; | 162 | return -ENOSYS; |
163 | } | 163 | } |
164 | 164 | ||
165 | static inline int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) | 165 | static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) |
166 | { | 166 | { |
167 | return -ENOSYS; | 167 | return -ENOSYS; |
168 | } | 168 | } |