diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-12 14:50:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-12 14:50:33 -0500 |
commit | be23c9d20b341a58ad7107f9e9aa5735cea3da13 (patch) | |
tree | da5e5ede73ccba5e3464821fb0cfb67c027f796a /drivers/base/power/opp/core.c | |
parent | 5d50ac70fe98518dbf620bfba8184254663125eb (diff) | |
parent | f57ab32a843690fe7431ebb3a2f461e689a2e3c7 (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.c | 44 |
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 | */ |
28 | static LIST_HEAD(dev_opp_list); | 30 | static 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 */ |
30 | static DEFINE_MUTEX(dev_opp_list_lock); | 32 | DEFINE_MUTEX(dev_opp_list_lock); |
31 | 33 | ||
32 | #define opp_rcu_lockdep_assert() \ | 34 | #define opp_rcu_lockdep_assert() \ |
33 | do { \ | 35 | do { \ |
@@ -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 | */ |
86 | struct device_opp *_find_device_opp(struct device *dev) | 90 | struct 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 | */ |
730 | static int _opp_add_dynamic(struct device *dev, unsigned long freq, | 736 | static 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 */ |
773 | static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev) | 779 | static 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 | */ |
940 | int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | 947 | int 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 | } |
944 | EXPORT_SYMBOL_GPL(dev_pm_opp_add); | 951 | EXPORT_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 | ||
1210 | free_table: | 1226 | free_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; |