aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/opp/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-12 14:50:33 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-12 14:50:33 -0500
commitbe23c9d20b341a58ad7107f9e9aa5735cea3da13 (patch)
treeda5e5ede73ccba5e3464821fb0cfb67c027f796a /drivers/base/power/opp/core.c
parent5d50ac70fe98518dbf620bfba8184254663125eb (diff)
parentf57ab32a843690fe7431ebb3a2f461e689a2e3c7 (diff)
Merge tag 'pm+acpi-4.4-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more power management and ACPI updates from Rafael Wysocki: "The only new feature in this batch is support for the ACPI _CCA device configuration object, which it a pre-requisite for future ACPI PCI support on ARM64, but should not affect the other architectures. The rest is fixes and cleanups, mostly in cpufreq (including intel_pstate), the Operating Performace Points (OPP) framework and tools (cpupower and turbostat). Specifics: - Support for the ACPI _CCA configuration object intended to tell the OS whether or not a bus master device supports hardware managed cache coherency and a new set of functions to allow drivers to check the cache coherency support for devices in a platform firmware interface agnostic way (Suravee Suthikulpanit, Jeremy Linton). - ACPI backlight quirks for ESPRIMO Mobile M9410 and Dell XPS L421X (Aaron Lu, Hans de Goede). - Fixes for the arm_big_little and s5pv210-cpufreq cpufreq drivers (Jon Medhurst, Nicolas Pitre). - kfree()-related fixup for the recently introduced CPPC cpufreq frontend (Markus Elfring). - intel_pstate fix reducing kernel log noise on systems where P-states are managed by hardware (Prarit Bhargava). - intel_pstate maintainers information update (Srinivas Pandruvada). - cpufreq core optimization related to the handling of delayed work items used by governors (Viresh Kumar). - Locking fixes and cleanups of the Operating Performance Points (OPP) framework (Viresh Kumar). - Generic power domains framework cleanups (Lina Iyer). - cpupower tool updates (Jacob Tanenbaum, Sriram Raghunathan, Thomas Renninger). - turbostat tool updates (Len Brown)" * tag 'pm+acpi-4.4-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (32 commits) PCI: ACPI: Add support for PCI device DMA coherency PCI: OF: Move of_pci_dma_configure() to pci_dma_configure() of/pci: Fix pci_get_host_bridge_device leak device property: ACPI: Remove unused DMA APIs device property: ACPI: Make use of the new DMA Attribute APIs device property: Adding DMA Attribute APIs for Generic Devices ACPI: Adding DMA Attribute APIs for ACPI Device device property: Introducing enum dev_dma_attr ACPI: Honor ACPI _CCA attribute setting cpufreq: CPPC: Delete an unnecessary check before the function call kfree() PM / OPP: Add opp_rcu_lockdep_assert() to _find_device_opp() PM / OPP: Hold dev_opp_list_lock for writers PM / OPP: Protect updates to list_dev with mutex PM / OPP: Propagate error properly from dev_pm_opp_set_sharing_cpus() cpufreq: s5pv210-cpufreq: fix wrong do_div() usage MAINTAINERS: update for intel P-state driver Creating a common structure initialization pattern for struct option cpupower: Enable disabled Cstates if they are below max latency cpupower: Remove debug message when using cpupower idle-set -D switch cpupower: cpupower monitor reports uninitialized values for offline cpus ...
Diffstat (limited to 'drivers/base/power/opp/core.c')
-rw-r--r--drivers/base/power/opp/core.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 270902007055..b8e76f75073b 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -11,6 +11,8 @@
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13 13
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
14#include <linux/errno.h> 16#include <linux/errno.h>
15#include <linux/err.h> 17#include <linux/err.h>
16#include <linux/slab.h> 18#include <linux/slab.h>
@@ -27,7 +29,7 @@
27 */ 29 */
28static LIST_HEAD(dev_opp_list); 30static LIST_HEAD(dev_opp_list);
29/* Lock to allow exclusive modification to the device and opp lists */ 31/* Lock to allow exclusive modification to the device and opp lists */
30static DEFINE_MUTEX(dev_opp_list_lock); 32DEFINE_MUTEX(dev_opp_list_lock);
31 33
32#define opp_rcu_lockdep_assert() \ 34#define opp_rcu_lockdep_assert() \
33do { \ 35do { \
@@ -79,14 +81,18 @@ static struct device_opp *_managed_opp(const struct device_node *np)
79 * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or 81 * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
80 * -EINVAL based on type of error. 82 * -EINVAL based on type of error.
81 * 83 *
82 * Locking: This function must be called under rcu_read_lock(). device_opp 84 * Locking: For readers, this function must be called under rcu_read_lock().
83 * is a RCU protected pointer. This means that device_opp is valid as long 85 * device_opp is a RCU protected pointer, which means that device_opp is valid
84 * as we are under RCU lock. 86 * as long as we are under RCU lock.
87 *
88 * For Writers, this function must be called with dev_opp_list_lock held.
85 */ 89 */
86struct device_opp *_find_device_opp(struct device *dev) 90struct device_opp *_find_device_opp(struct device *dev)
87{ 91{
88 struct device_opp *dev_opp; 92 struct device_opp *dev_opp;
89 93
94 opp_rcu_lockdep_assert();
95
90 if (IS_ERR_OR_NULL(dev)) { 96 if (IS_ERR_OR_NULL(dev)) {
91 pr_err("%s: Invalid parameters\n", __func__); 97 pr_err("%s: Invalid parameters\n", __func__);
92 return ERR_PTR(-EINVAL); 98 return ERR_PTR(-EINVAL);
@@ -701,7 +707,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
701} 707}
702 708
703/** 709/**
704 * _opp_add_dynamic() - Allocate a dynamic OPP. 710 * _opp_add_v1() - Allocate a OPP based on v1 bindings.
705 * @dev: device for which we do this operation 711 * @dev: device for which we do this operation
706 * @freq: Frequency in Hz for this OPP 712 * @freq: Frequency in Hz for this OPP
707 * @u_volt: Voltage in uVolts for this OPP 713 * @u_volt: Voltage in uVolts for this OPP
@@ -727,8 +733,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
727 * Duplicate OPPs (both freq and volt are same) and !opp->available 733 * Duplicate OPPs (both freq and volt are same) and !opp->available
728 * -ENOMEM Memory allocation failure 734 * -ENOMEM Memory allocation failure
729 */ 735 */
730static int _opp_add_dynamic(struct device *dev, unsigned long freq, 736static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
731 long u_volt, bool dynamic) 737 bool dynamic)
732{ 738{
733 struct device_opp *dev_opp; 739 struct device_opp *dev_opp;
734 struct dev_pm_opp *new_opp; 740 struct dev_pm_opp *new_opp;
@@ -770,9 +776,10 @@ unlock:
770} 776}
771 777
772/* TODO: Support multiple regulators */ 778/* TODO: Support multiple regulators */
773static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev) 779static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev)
774{ 780{
775 u32 microvolt[3] = {0}; 781 u32 microvolt[3] = {0};
782 u32 val;
776 int count, ret; 783 int count, ret;
777 784
778 /* Missing property isn't a problem, but an invalid entry is */ 785 /* Missing property isn't a problem, but an invalid entry is */
@@ -805,6 +812,9 @@ static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev)
805 opp->u_volt_min = microvolt[1]; 812 opp->u_volt_min = microvolt[1];
806 opp->u_volt_max = microvolt[2]; 813 opp->u_volt_max = microvolt[2];
807 814
815 if (!of_property_read_u32(opp->np, "opp-microamp", &val))
816 opp->u_amp = val;
817
808 return 0; 818 return 0;
809} 819}
810 820
@@ -869,13 +879,10 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
869 if (!of_property_read_u32(np, "clock-latency-ns", &val)) 879 if (!of_property_read_u32(np, "clock-latency-ns", &val))
870 new_opp->clock_latency_ns = val; 880 new_opp->clock_latency_ns = val;
871 881
872 ret = opp_get_microvolt(new_opp, dev); 882 ret = opp_parse_supplies(new_opp, dev);
873 if (ret) 883 if (ret)
874 goto free_opp; 884 goto free_opp;
875 885
876 if (!of_property_read_u32(new_opp->np, "opp-microamp", &val))
877 new_opp->u_amp = val;
878
879 ret = _opp_add(dev, new_opp, dev_opp); 886 ret = _opp_add(dev, new_opp, dev_opp);
880 if (ret) 887 if (ret)
881 goto free_opp; 888 goto free_opp;
@@ -939,7 +946,7 @@ unlock:
939 */ 946 */
940int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) 947int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
941{ 948{
942 return _opp_add_dynamic(dev, freq, u_volt, true); 949 return _opp_add_v1(dev, freq, u_volt, true);
943} 950}
944EXPORT_SYMBOL_GPL(dev_pm_opp_add); 951EXPORT_SYMBOL_GPL(dev_pm_opp_add);
945 952
@@ -1172,13 +1179,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
1172 struct device_opp *dev_opp; 1179 struct device_opp *dev_opp;
1173 int ret = 0, count = 0; 1180 int ret = 0, count = 0;
1174 1181
1182 mutex_lock(&dev_opp_list_lock);
1183
1175 dev_opp = _managed_opp(opp_np); 1184 dev_opp = _managed_opp(opp_np);
1176 if (dev_opp) { 1185 if (dev_opp) {
1177 /* OPPs are already managed */ 1186 /* OPPs are already managed */
1178 if (!_add_list_dev(dev, dev_opp)) 1187 if (!_add_list_dev(dev, dev_opp))
1179 ret = -ENOMEM; 1188 ret = -ENOMEM;
1189 mutex_unlock(&dev_opp_list_lock);
1180 return ret; 1190 return ret;
1181 } 1191 }
1192 mutex_unlock(&dev_opp_list_lock);
1182 1193
1183 /* We have opp-list node now, iterate over it and add OPPs */ 1194 /* We have opp-list node now, iterate over it and add OPPs */
1184 for_each_available_child_of_node(opp_np, np) { 1195 for_each_available_child_of_node(opp_np, np) {
@@ -1196,15 +1207,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
1196 if (WARN_ON(!count)) 1207 if (WARN_ON(!count))
1197 return -ENOENT; 1208 return -ENOENT;
1198 1209
1210 mutex_lock(&dev_opp_list_lock);
1211
1199 dev_opp = _find_device_opp(dev); 1212 dev_opp = _find_device_opp(dev);
1200 if (WARN_ON(IS_ERR(dev_opp))) { 1213 if (WARN_ON(IS_ERR(dev_opp))) {
1201 ret = PTR_ERR(dev_opp); 1214 ret = PTR_ERR(dev_opp);
1215 mutex_unlock(&dev_opp_list_lock);
1202 goto free_table; 1216 goto free_table;
1203 } 1217 }
1204 1218
1205 dev_opp->np = opp_np; 1219 dev_opp->np = opp_np;
1206 dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared"); 1220 dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
1207 1221
1222 mutex_unlock(&dev_opp_list_lock);
1223
1208 return 0; 1224 return 0;
1209 1225
1210free_table: 1226free_table:
@@ -1241,7 +1257,7 @@ static int _of_add_opp_table_v1(struct device *dev)
1241 unsigned long freq = be32_to_cpup(val++) * 1000; 1257 unsigned long freq = be32_to_cpup(val++) * 1000;
1242 unsigned long volt = be32_to_cpup(val++); 1258 unsigned long volt = be32_to_cpup(val++);
1243 1259
1244 if (_opp_add_dynamic(dev, freq, volt, false)) 1260 if (_opp_add_v1(dev, freq, volt, false))
1245 dev_warn(dev, "%s: Failed to add OPP %ld\n", 1261 dev_warn(dev, "%s: Failed to add OPP %ld\n",
1246 __func__, freq); 1262 __func__, freq);
1247 nr -= 2; 1263 nr -= 2;