diff options
| -rw-r--r-- | Documentation/power/opp.txt | 25 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 2 | ||||
| -rw-r--r-- | drivers/base/power/power.h | 8 | ||||
| -rw-r--r-- | drivers/base/power/qos.c | 217 | ||||
| -rw-r--r-- | drivers/base/power/sysfs.c | 1 | ||||
| -rw-r--r-- | drivers/cpufreq/cpufreq_governor.h | 2 | ||||
| -rw-r--r-- | drivers/cpufreq/highbank-cpufreq.c | 8 | ||||
| -rw-r--r-- | drivers/cpufreq/intel_pstate.c | 42 | ||||
| -rw-r--r-- | drivers/mailbox/pl320-ipc.c | 3 |
9 files changed, 163 insertions, 145 deletions
diff --git a/Documentation/power/opp.txt b/Documentation/power/opp.txt index 3035d00757ad..425c51d56aef 100644 --- a/Documentation/power/opp.txt +++ b/Documentation/power/opp.txt | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | *=============* | 1 | Operating Performance Points (OPP) Library |
| 2 | * OPP Library * | 2 | ========================================== |
| 3 | *=============* | ||
| 4 | 3 | ||
| 5 | (C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated | 4 | (C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated |
| 6 | 5 | ||
| @@ -16,15 +15,31 @@ Contents | |||
| 16 | 15 | ||
| 17 | 1. Introduction | 16 | 1. Introduction |
| 18 | =============== | 17 | =============== |
| 18 | 1.1 What is an Operating Performance Point (OPP)? | ||
| 19 | |||
| 19 | Complex SoCs of today consists of a multiple sub-modules working in conjunction. | 20 | Complex SoCs of today consists of a multiple sub-modules working in conjunction. |
| 20 | In an operational system executing varied use cases, not all modules in the SoC | 21 | In an operational system executing varied use cases, not all modules in the SoC |
| 21 | need to function at their highest performing frequency all the time. To | 22 | need to function at their highest performing frequency all the time. To |
| 22 | facilitate this, sub-modules in a SoC are grouped into domains, allowing some | 23 | facilitate this, sub-modules in a SoC are grouped into domains, allowing some |
| 23 | domains to run at lower voltage and frequency while other domains are loaded | 24 | domains to run at lower voltage and frequency while other domains run at |
| 24 | more. The set of discrete tuples consisting of frequency and voltage pairs that | 25 | voltage/frequency pairs that are higher. |
| 26 | |||
| 27 | The set of discrete tuples consisting of frequency and voltage pairs that | ||
| 25 | the device will support per domain are called Operating Performance Points or | 28 | the device will support per domain are called Operating Performance Points or |
| 26 | OPPs. | 29 | OPPs. |
| 27 | 30 | ||
| 31 | As an example: | ||
| 32 | Let us consider an MPU device which supports the following: | ||
| 33 | {300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V}, | ||
| 34 | {1GHz at minimum voltage of 1.3V} | ||
| 35 | |||
| 36 | We can represent these as three OPPs as the following {Hz, uV} tuples: | ||
| 37 | {300000000, 1000000} | ||
| 38 | {800000000, 1200000} | ||
| 39 | {1000000000, 1300000} | ||
| 40 | |||
| 41 | 1.2 Operating Performance Points Library | ||
| 42 | |||
| 28 | OPP library provides a set of helper functions to organize and query the OPP | 43 | OPP library provides a set of helper functions to organize and query the OPP |
| 29 | information. The library is located in drivers/base/power/opp.c and the header | 44 | information. The library is located in drivers/base/power/opp.c and the header |
| 30 | is located in include/linux/opp.h. OPP library can be enabled by enabling | 45 | is located in include/linux/opp.h. OPP library can be enabled by enabling |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2b7f77d3fcb0..15beb500a4e4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
| @@ -99,7 +99,6 @@ void device_pm_add(struct device *dev) | |||
| 99 | dev_warn(dev, "parent %s should not be sleeping\n", | 99 | dev_warn(dev, "parent %s should not be sleeping\n", |
| 100 | dev_name(dev->parent)); | 100 | dev_name(dev->parent)); |
| 101 | list_add_tail(&dev->power.entry, &dpm_list); | 101 | list_add_tail(&dev->power.entry, &dpm_list); |
| 102 | dev_pm_qos_constraints_init(dev); | ||
| 103 | mutex_unlock(&dpm_list_mtx); | 102 | mutex_unlock(&dpm_list_mtx); |
| 104 | } | 103 | } |
| 105 | 104 | ||
| @@ -113,7 +112,6 @@ void device_pm_remove(struct device *dev) | |||
| 113 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); | 112 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
| 114 | complete_all(&dev->power.completion); | 113 | complete_all(&dev->power.completion); |
| 115 | mutex_lock(&dpm_list_mtx); | 114 | mutex_lock(&dpm_list_mtx); |
| 116 | dev_pm_qos_constraints_destroy(dev); | ||
| 117 | list_del_init(&dev->power.entry); | 115 | list_del_init(&dev->power.entry); |
| 118 | mutex_unlock(&dpm_list_mtx); | 116 | mutex_unlock(&dpm_list_mtx); |
| 119 | device_wakeup_disable(dev); | 117 | device_wakeup_disable(dev); |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index b16686a0a5a2..cfc3226ec492 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
| @@ -4,7 +4,7 @@ static inline void device_pm_init_common(struct device *dev) | |||
| 4 | { | 4 | { |
| 5 | if (!dev->power.early_init) { | 5 | if (!dev->power.early_init) { |
| 6 | spin_lock_init(&dev->power.lock); | 6 | spin_lock_init(&dev->power.lock); |
| 7 | dev->power.power_state = PMSG_INVALID; | 7 | dev->power.qos = NULL; |
| 8 | dev->power.early_init = true; | 8 | dev->power.early_init = true; |
| 9 | } | 9 | } |
| 10 | } | 10 | } |
| @@ -56,14 +56,10 @@ extern void device_pm_move_last(struct device *); | |||
| 56 | 56 | ||
| 57 | static inline void device_pm_sleep_init(struct device *dev) {} | 57 | static inline void device_pm_sleep_init(struct device *dev) {} |
| 58 | 58 | ||
| 59 | static inline void device_pm_add(struct device *dev) | 59 | static inline void device_pm_add(struct device *dev) {} |
| 60 | { | ||
| 61 | dev_pm_qos_constraints_init(dev); | ||
| 62 | } | ||
| 63 | 60 | ||
| 64 | static inline void device_pm_remove(struct device *dev) | 61 | static inline void device_pm_remove(struct device *dev) |
| 65 | { | 62 | { |
| 66 | dev_pm_qos_constraints_destroy(dev); | ||
| 67 | pm_runtime_remove(dev); | 63 | pm_runtime_remove(dev); |
| 68 | } | 64 | } |
| 69 | 65 | ||
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 3d4d1f8aac5c..5f74587ef258 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
| 42 | #include <linux/export.h> | 42 | #include <linux/export.h> |
| 43 | #include <linux/pm_runtime.h> | 43 | #include <linux/pm_runtime.h> |
| 44 | #include <linux/err.h> | ||
| 44 | 45 | ||
| 45 | #include "power.h" | 46 | #include "power.h" |
| 46 | 47 | ||
| @@ -61,7 +62,7 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) | |||
| 61 | struct pm_qos_flags *pqf; | 62 | struct pm_qos_flags *pqf; |
| 62 | s32 val; | 63 | s32 val; |
| 63 | 64 | ||
| 64 | if (!qos) | 65 | if (IS_ERR_OR_NULL(qos)) |
| 65 | return PM_QOS_FLAGS_UNDEFINED; | 66 | return PM_QOS_FLAGS_UNDEFINED; |
| 66 | 67 | ||
| 67 | pqf = &qos->flags; | 68 | pqf = &qos->flags; |
| @@ -101,7 +102,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags); | |||
| 101 | */ | 102 | */ |
| 102 | s32 __dev_pm_qos_read_value(struct device *dev) | 103 | s32 __dev_pm_qos_read_value(struct device *dev) |
| 103 | { | 104 | { |
| 104 | return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0; | 105 | return IS_ERR_OR_NULL(dev->power.qos) ? |
| 106 | 0 : pm_qos_read_value(&dev->power.qos->latency); | ||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | /** | 109 | /** |
| @@ -198,20 +200,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) | |||
| 198 | return 0; | 200 | return 0; |
| 199 | } | 201 | } |
| 200 | 202 | ||
| 201 | /** | 203 | static void __dev_pm_qos_hide_latency_limit(struct device *dev); |
| 202 | * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer. | 204 | static void __dev_pm_qos_hide_flags(struct device *dev); |
| 203 | * @dev: target device | ||
| 204 | * | ||
| 205 | * Called from the device PM subsystem during device insertion under | ||
| 206 | * device_pm_lock(). | ||
| 207 | */ | ||
| 208 | void dev_pm_qos_constraints_init(struct device *dev) | ||
| 209 | { | ||
| 210 | mutex_lock(&dev_pm_qos_mtx); | ||
| 211 | dev->power.qos = NULL; | ||
| 212 | dev->power.power_state = PMSG_ON; | ||
| 213 | mutex_unlock(&dev_pm_qos_mtx); | ||
| 214 | } | ||
| 215 | 205 | ||
| 216 | /** | 206 | /** |
| 217 | * dev_pm_qos_constraints_destroy | 207 | * dev_pm_qos_constraints_destroy |
| @@ -226,16 +216,15 @@ void dev_pm_qos_constraints_destroy(struct device *dev) | |||
| 226 | struct pm_qos_constraints *c; | 216 | struct pm_qos_constraints *c; |
| 227 | struct pm_qos_flags *f; | 217 | struct pm_qos_flags *f; |
| 228 | 218 | ||
| 219 | mutex_lock(&dev_pm_qos_mtx); | ||
| 220 | |||
| 229 | /* | 221 | /* |
| 230 | * If the device's PM QoS resume latency limit or PM QoS flags have been | 222 | * If the device's PM QoS resume latency limit or PM QoS flags have been |
| 231 | * exposed to user space, they have to be hidden at this point. | 223 | * exposed to user space, they have to be hidden at this point. |
| 232 | */ | 224 | */ |
| 233 | dev_pm_qos_hide_latency_limit(dev); | 225 | __dev_pm_qos_hide_latency_limit(dev); |
| 234 | dev_pm_qos_hide_flags(dev); | 226 | __dev_pm_qos_hide_flags(dev); |
| 235 | 227 | ||
| 236 | mutex_lock(&dev_pm_qos_mtx); | ||
| 237 | |||
| 238 | dev->power.power_state = PMSG_INVALID; | ||
| 239 | qos = dev->power.qos; | ||
