* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
@ 2011-12-14 14:51 jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 1/6] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
` (6 more replies)
0 siblings, 7 replies; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
. Implement the devices wake-up latency constraints using the global
device PM QoS notification handler which applies the constraints to the
underlying layer
. Implement the low level code which controls the power domains next power
states, through the hwmod and pwrdm layers
. Add cpuidle and power domains wake-up latency figures for OMAP3, cf.
comments in the code and [1] for the details on where the numbers
are magically coming from
. Implement the relation between the cpuidle and per-device PM QoS frameworks
in the OMAP3 specific idle callbacks.
The chosen C-state shall satisfy the following conditions:
. the 'valid' field is enabled,
. it satisfies the enable_off_mode flag,
. the next state for MPU and CORE power domains is not lower than the
state programmed by the per-device PM QoS.
ToDo:
1. support OMAP4 chipset when the low power modes will be supported
2. validate the constraints framework on OMAP4 HW (done on OMAP3)
3. Re-visit the OMAP power domains states initialization procedure. Currently
the power states that have been changed from the constraints API which were
applied before the initialization of the power domains are lost
4. Further clean-up the OMAP PM layer, use the generic frameworks instead (OPP,
PM QoS...)
Based on the pm-qos branch of the linux-omap git tree (3.2.0-rc4), cf. [2].
Tested on OMAP3 Beagleboard (ES2.x) with constraints on MPU, CORE, PER in
RETention and OFF modes.
[1] http://www.omappedia.org/wiki/Power_Management_Device_Latencies_Measurement
[2] git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
v6:
. minor change in the commits description after Kevin's review
. added Kevin's Reviewed-by
v5:
. rebased on latest linux-omap [2]
. rework after Kevin's comments on the MLs
v4:
. split up the patches which remove the omap_pm_ code from the patch set.
Those patches are to be submitted later, on top of this patch set.
. latency numbers: provide the measurements setup and conditions in the code
comments, added the link to the details on wiki [1].
. improved kerneldoc
. split big functions into smaller ones, in order to improve the readability
v3: reworked the error return path and improved the kerneldoc
v2: reworked the OMAP specific cpuidle code to demote the initial C-state to
a valid C-state which fulfills the per-device constraints
v1: initial version
Jean Pihet (6):
OMAP2+: powerdomain: control power domains next state
OMAP2+: omap_hwmod: manage the wake-up latency constraints
OMAP: PM: register to the per-device PM QoS framework
OMAP3: cpuidle: next C-state decision depends on the PM QoS MPU and
CORE constraints
OMAP3: update cpuidle latency and threshold figures
OMAP3: powerdomain data: add wake-up latency figures
arch/arm/mach-omap2/cpuidle34xx.c | 107 +++++++-----
arch/arm/mach-omap2/omap_hwmod.c | 27 +++-
arch/arm/mach-omap2/pm.c | 71 ++++++++-
arch/arm/mach-omap2/pm.h | 17 ++-
arch/arm/mach-omap2/powerdomain.c | 245 ++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 36 ++++-
arch/arm/mach-omap2/powerdomains3xxx_data.c | 83 +++++++++
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +
8 files changed, 539 insertions(+), 49 deletions(-)
--
1.7.5.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/6] OMAP2+: powerdomain: control power domains next state
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet at newoldbits.com
` (5 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
When a PM QoS device latency constraint is requested or removed the
PM QoS layer notifies the underlying layer with the updated aggregated
constraint value. The constraint is stored in the powerdomain constraints
list and then applied to the corresponding power domain.
The power domains get the next power state programmed directly in the
registers via pwrdm_wakeuplat_update_pwrst.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using
wake-up latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/powerdomain.c | 245 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 36 +++++-
2 files changed, 279 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 8a18d1b..677a182 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -17,8 +17,10 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/pm_qos.h>
#include <trace/events/power.h>
#include "cm2xxx_3xxx.h"
@@ -112,6 +114,12 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
for (i = 0; i < pwrdm->banks; i++)
pwrdm->ret_mem_off_counter[i] = 0;
+ /* Initialize the per-device wake-up constraints framework data */
+ spin_lock_init(&pwrdm->wkup_lat_plist_lock);
+ plist_head_init(&pwrdm->wkup_lat_plist_head);
+ pwrdm->wkup_lat_next_state = PWRDM_POWER_OFF;
+
+ /* Initialize the pwrdm state */
pwrdm_wait_transition(pwrdm);
pwrdm->state = pwrdm_read_pwrst(pwrdm);
pwrdm->state_counter[pwrdm->state] = 1;
@@ -199,6 +207,158 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
return 0;
}
+/**
+ * _pwrdm_wakeuplat_update_list - Set/update/remove a powerdomain wakeup
+ * latency constraint from the pwrdm's constraint list
+ * @pwrdm: struct powerdomain * which the constraint applies to
+ * @cookie: constraint identifier, used for tracking.
+ * @min_latency: minimum wakeup latency constraint (in microseconds) for
+ * the given pwrdm. The value of PM_QOS_DEV_LAT_DEFAULT_VALUE removes
+ * the constraint.
+ * @user: pointer to the current list entry
+ * @new_user: allocated list entry, used for insertion of new constraints
+ * in the list
+ * @free_new_user: set to non-zero if the newly allocated list entry
+ * is unused and needs to be freed
+ * @free_node: set to non-zero if the current list entry is not in use
+ * anymore and needs to be freed
+ *
+ * Tracks the constraints by @cookie.
+ * Constraint set/update: Adds a new entry to powerdomain's wake-up latency
+ * constraint list.
+ * If the constraint identifier already exists in the list, the old value is
+ * overwritten.
+ * Constraint removal: Removes the identifier's entry from powerdomain's
+ * wakeup latency constraint list.
+ *
+ * Called with the pwrdm wakeup latency spinlock held.
+ *
+ * Returns 0 upon success, -EINVAL if the constraint is not existing.
+ */
+static inline int _pwrdm_update_wakeuplat_list(
+ struct powerdomain *pwrdm,
+ void *cookie,
+ long min_latency,
+ struct pwrdm_wkup_constraints_entry *user,
+ struct pwrdm_wkup_constraints_entry *new_user,
+ int *free_new_user,
+ int *free_node)
+{
+ struct pwrdm_wkup_constraints_entry *tmp_user;
+
+ /* Check if there already is a constraint for cookie */
+ plist_for_each_entry(tmp_user, &pwrdm->wkup_lat_plist_head, node) {
+ if (tmp_user->cookie == cookie) {
+ user = tmp_user;
+ break;
+ }
+ }
+
+ if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
+ /* If nothing to update, job done */
+ if (user && (user->node.prio == min_latency))
+ return 0;
+
+ if (!user) {
+ /* Add new entry to the list */
+ user = new_user;
+ user->cookie = cookie;
+ *free_new_user = 0;
+ } else {
+ /* Update existing entry */
+ plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+ }
+
+ plist_node_init(&user->node, min_latency);
+ plist_add(&user->node, &pwrdm->wkup_lat_plist_head);
+ } else {
+ if (user) {
+ /* Remove the constraint from the list */
+ plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+ *free_node = 1;
+ } else {
+ /* Constraint not existing or list empty, do nothing */
+ return -EINVAL;
+ }
+
+ }
+
+ return 0;
+}
+
+/**
+ * _pwrdm_wakeuplat_update_pwrst - Update power domain power state if needed
+ * @pwrdm: struct powerdomain * to which requesting device belongs to.
+ * @min_latency: the allowed wake-up latency for the given power domain. A
+ * value of PM_QOS_DEV_LAT_DEFAULT_VALUE means 'no constraint' on the pwrdm.
+ *
+ * Finds the power domain next power state that fulfills the constraint.
+ * Programs a new target state if it is different from current power state.
+ * The power domains get the next power state programmed directly in the
+ * registers.
+ *
+ * Returns 0 in case of success, -EINVAL in case of invalid parameters,
+ * or the return value from omap_set_pwrdm_state.
+ */
+static int _pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm,
+ long min_latency)
+{
+ int ret = 0, new_state;
+
+ if (!pwrdm) {
+ WARN(1, "powerdomain: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Find the next supported power state with
+ * wakeup latency < minimum constraint
+ */
+ for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) {
+ if (min_latency == PM_QOS_DEV_LAT_DEFAULT_VALUE)
+ break;
+ if ((pwrdm->wakeup_lat[new_state] != UNSUP_STATE) &&
+ (pwrdm->wakeup_lat[new_state] <= min_latency))
+ break;
+ }
+
+ switch (new_state) {
+ case PWRDM_FUNC_PWRST_OFF:
+ new_state = PWRDM_POWER_OFF;
+ break;
+ case PWRDM_FUNC_PWRST_OSWR:
+ pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_OFF);
+ new_state = PWRDM_POWER_RET;
+ break;
+ case PWRDM_FUNC_PWRST_CSWR:
+ pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_RET);
+ new_state = PWRDM_POWER_RET;
+ break;
+ case PWRDM_FUNC_PWRST_INACTIVE:
+ new_state = PWRDM_POWER_INACTIVE;
+ break;
+ case PWRDM_FUNC_PWRST_ON:
+ new_state = PWRDM_POWER_ON;
+ break;
+ default:
+ pr_warn("powerdomain: requested latency constraint not "
+ "supported %s set to ON state\n", pwrdm->name);
+ new_state = PWRDM_POWER_ON;
+ break;
+ }
+
+ pwrdm->wkup_lat_next_state = new_state;
+ if (pwrdm_read_next_pwrst(pwrdm) != new_state)
+ ret = omap_set_pwrdm_state(pwrdm, new_state);
+
+ pr_debug("powerdomain: %s pwrst: curr=%d, prev=%d next=%d "
+ "min_latency=%ld, set_state=%d\n", pwrdm->name,
+ pwrdm_read_pwrst(pwrdm), pwrdm_read_prev_pwrst(pwrdm),
+ pwrdm_read_next_pwrst(pwrdm), min_latency, new_state);
+
+ return ret;
+}
+
/* Public functions */
/**
@@ -998,6 +1158,91 @@ int pwrdm_post_transition(void)
}
/**
+ * pwrdm_set_wkup_lat_constraint - Set/update/remove a powerdomain wakeup
+ * latency constraint and apply it
+ * @pwrdm: struct powerdomain * which the constraint applies to
+ * @cookie: constraint identifier, used for tracking.
+ * @min_latency: minimum wakeup latency constraint (in microseconds) for
+ * the given pwrdm. The value of PM_QOS_DEV_LAT_DEFAULT_VALUE removes
+ * the constraint.
+ *
+ * Tracks the constraints by @cookie.
+ * Constraint set/update: Adds a new entry to powerdomain's wake-up latency
+ * constraint list.
+ * If the constraint identifier already exists in the list, the old value is
+ * overwritten.
+ * Constraint removal: Removes the identifier's entry from powerdomain's
+ * wakeup latency constraint list.
+ *
+ * Applies the aggregated constraint value for the given pwrdm by calling
+ * _pwrdm_wakeuplat_update_pwrst.
+ *
+ * Returns 0 upon success, -ENOMEM in case of memory shortage, -EINVAL in
+ * case of invalid parameters, or the return value from
+ * _pwrdm_wakeuplat_update_pwrst.
+ *
+ * The caller must check the validity of the parameters.
+ *
+ * Note about the resources allocation and release:
+ * The free_new_user and free_node variables are used to indicate
+ * if the allocated resources can be freed, respectively for the
+ * newly allocated list entry and the current list entry.
+ * Cf. kerneldoc for the _pwrdm_update_wakeuplat_list function for
+ * detailed information about those variables and the
+ * allocation and release of the constraints list entries.
+ */
+int pwrdm_set_wkup_lat_constraint(struct powerdomain *pwrdm, void *cookie,
+ long min_latency)
+{
+ struct pwrdm_wkup_constraints_entry *user = NULL, *new_user = NULL;
+ int ret = 0, free_new_user = 0, free_node = 0;
+ long value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+ unsigned long flags;
+
+ pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
+ __func__, pwrdm->name, cookie, min_latency);
+
+ if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
+ new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
+ GFP_KERNEL);
+ if (!new_user) {
+ pr_err("%s: FATAL ERROR: kzalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+ free_new_user = 1;
+ }
+
+ spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+
+ /* Manage the constraints list */
+ ret = _pwrdm_update_wakeuplat_list(pwrdm, cookie, min_latency,
+ user, new_user,
+ &free_new_user, &free_node);
+
+ /* Find the aggregated constraint value from the list */
+ if (!ret)
+ if (!plist_head_empty(&pwrdm->wkup_lat_plist_head))
+ value = plist_first(&pwrdm->wkup_lat_plist_head)->prio;
+
+ spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+ if (free_node)
+ kfree(user);
+
+ if (free_new_user)
+ kfree(new_user);
+
+ /* Apply the constraint to the pwrdm */
+ if (!ret) {
+ pr_debug("powerdomain: %s: pwrdm %s, value=%ld\n",
+ __func__, pwrdm->name, value);
+ ret = _pwrdm_wakeuplat_update_pwrst(pwrdm, value);
+ }
+
+ return ret;
+}
+
+/**
* pwrdm_get_context_loss_count - get powerdomain's context loss count
* @pwrdm: struct powerdomain * to wait for
*
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 0d72a8a..b4a60cf 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -19,7 +19,9 @@
#include <linux/types.h>
#include <linux/list.h>
-
+#include <linux/plist.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/atomic.h>
#include <plat/cpu.h>
@@ -45,6 +47,16 @@
#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON)
#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON)
+/* Powerdomain functional power states */
+#define PWRDM_FUNC_PWRST_OFF 0x0
+#define PWRDM_FUNC_PWRST_OSWR 0x1
+#define PWRDM_FUNC_PWRST_CSWR 0x2
+#define PWRDM_FUNC_PWRST_INACTIVE 0x3
+#define PWRDM_FUNC_PWRST_ON 0x4
+
+#define PWRDM_MAX_FUNC_PWRSTS 5
+
+#define UNSUP_STATE -1
/* Powerdomain flags */
#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */
@@ -96,7 +108,13 @@ struct powerdomain;
* @state_counter:
* @timer:
* @state_timer:
- *
+ * @wakeup_lat: wakeup latencies (in us) for possible powerdomain power states
+ * Note about the wakeup latencies ordering: the values must be sorted
+ * in decremental order
+ * @wkup_lat_plist_head: pwrdm wake-up latency constraints list
+ * @wkup_lat_plist_lock: spinlock that protects the constraints lists
+ * domains states
+ * @wkup_lat_next_state: next pwrdm state, calculated from the constraints list
* @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
*/
struct powerdomain {
@@ -125,6 +143,16 @@ struct powerdomain {
s64 timer;
s64 state_timer[PWRDM_MAX_PWRSTS];
#endif
+ const s32 wakeup_lat[PWRDM_MAX_FUNC_PWRSTS];
+ struct plist_head wkup_lat_plist_head;
+ spinlock_t wkup_lat_plist_lock;
+ int wkup_lat_next_state;
+};
+
+/* Linked list for the wake-up latency constraints */
+struct pwrdm_wkup_constraints_entry {
+ void *cookie;
+ struct plist_node node;
};
/**
@@ -217,6 +245,10 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
int pwrdm_pre_transition(void);
int pwrdm_post_transition(void);
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
+
+int pwrdm_set_wkup_lat_constraint(struct powerdomain *pwrdm, void *cookie,
+ long min_latency);
+
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 1/6] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-19 21:11 ` Paul Walmsley
2011-12-14 14:51 ` [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework jean.pihet at newoldbits.com
` (4 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
The OMAP PM code implements a handler for the per-device PM QoS framework.
The handler queries the omap_hwmod layer in order to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 27 +++++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +
2 files changed, 28 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 529142a..c3a4cc4 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -143,6 +143,7 @@
#include "powerdomain.h"
#include <plat/clock.h>
#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include <plat/prcm.h>
#include "cm2xxx_3xxx.h"
@@ -2616,10 +2617,34 @@ ohsps_unlock:
}
/**
+ * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
+ *
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Returns 0 upon success, -EINVAL in case of invalid parameters, or
+ * the return value from pwrdm_set_wkup_lat_constraint.
+ */
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
+ void *cookie, long min_latency)
+{
+ struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+ if (!pwrdm) {
+ pr_err("%s: Error: could not find powerdomain "
+ "for %s\n", __func__, oh->name);
+ return -EINVAL;
+ }
+
+ return pwrdm_set_wkup_lat_constraint(pwrdm, cookie, min_latency);
+}
+
+/**
* omap_hwmod_get_context_loss_count - get lost context count
* @oh: struct omap_hwmod *
*
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
* count for this device.
*
* Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 8b372ed..222f792 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -600,6 +600,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
void *user);
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh, void *cookie,
+ long min_latency);
int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 1/6] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-19 21:12 ` Paul Walmsley
2011-12-14 14:51 ` [PATCH 4/6] OMAP3: cpuidle: next C-state decision depends on the PM QoS MPU and CORE constraints jean.pihet at newoldbits.com
` (3 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
Implement the devices wake-up latency constraints using the global
device PM QoS notification handler which applies the constraints to the
underlying layer by calling the corresponding function at hwmod level.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/pm.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 70 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 1881fe9..a40d4f3 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -11,15 +11,18 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/notifier.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/opp.h>
+#include <linux/pm_qos.h>
#include <linux/export.h>
#include <plat/omap-pm.h>
#include <plat/omap_device.h>
-#include "common.h"
+#include <plat/omap_hwmod.h>
+#include "common.h"
#include "voltage.h"
#include "powerdomain.h"
#include "clockdomain.h"
@@ -215,12 +218,78 @@ static void __init omap4_init_voltages(void)
omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", "iva");
}
+/* Interface to the per-device PM QoS framework */
+static int omap2_dev_pm_qos_handler(struct notifier_block *nb,
+ unsigned long new_value,
+ void *req)
+{
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request *dev_pm_qos_req = req;
+
+ pr_debug("OMAP PM constraints: req at 0x%p, new_value=%lu\n",
+ req, new_value);
+
+ /* Look for the platform device for the constraint target device */
+ pdev = to_platform_device(dev_pm_qos_req->dev);
+
+ /* Try to catch non platform devices */
+ if (pdev->name == NULL) {
+ pr_err("%s: Error: platform device for device %s not valid\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return -EINVAL;
+ }
+
+ /* Find the associated omap_device for dev */
+ od = to_omap_device(pdev);
+ if (od == NULL) {
+ pr_err("%s: Error: no omap_device for device %s\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return -EINVAL;
+ }
+
+ /* Check that the omap_device has an unique hwmod entry */
+ if (od->hwmods_cnt != 1) {
+ pr_err("%s: Error: No unique hwmod for device %s\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return -EINVAL;
+ }
+
+ /* Find the primary omap_hwmod for dev */
+ oh = od->hwmods[0];
+
+ pr_debug("OMAP PM constraints: req at 0x%p, dev=0x%p, new_value=%lu\n",
+ req, dev_pm_qos_req->dev, new_value);
+
+ /* Apply the constraint */
+ return omap_hwmod_set_wkup_lat_constraint(oh, dev_pm_qos_req,
+ new_value);
+}
+
+static struct notifier_block omap2_dev_pm_qos_notifier = {
+ .notifier_call = omap2_dev_pm_qos_handler,
+};
+
+static int __init omap2_dev_pm_qos_init(void)
+{
+ int ret;
+
+ ret = dev_pm_qos_add_global_notifier(&omap2_dev_pm_qos_notifier);
+ WARN(ret, KERN_ERR "Cannot add global notifier for dev PM QoS\n");
+
+ return ret;
+}
+
static int __init omap2_common_pm_init(void)
{
if (!of_have_populated_dt())
omap2_init_processor_devices();
omap_pm_if_init();
+ /* Register to the per-device PM QoS framework */
+ omap2_dev_pm_qos_init();
+
return 0;
}
postcore_initcall(omap2_common_pm_init);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/6] OMAP3: cpuidle: next C-state decision depends on the PM QoS MPU and CORE constraints
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
` (2 preceding siblings ...)
2011-12-14 14:51 ` [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 5/6] OMAP3: update cpuidle latency and threshold figures jean.pihet at newoldbits.com
` (2 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
The MPU latency figures for cpuidle include the MPU itself and also
the peripherals needed for the MPU to execute instructions (e.g.
main memory, caches, IRQ controller, MMU etc). On OMAP3 those
peripherals belong to the MPU and CORE power domains and so the
cpuidle C-states are a combination of MPU and CORE states.
This patch implements the relation between the cpuidle and per-
device PM QoS frameworks in the OMAP3 specific idle callbacks.
The chosen C-state shall satisfy the following conditions:
. the 'valid' field is enabled,
. it satisfies the enable_off_mode flag,
. the next state for MPU and CORE power domains is not lower than the
next state calculated by the per-device PM QoS.
Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/cpuidle34xx.c | 57 ++++++++++++++++++++----------------
arch/arm/mach-omap2/pm.h | 17 ++++++++++-
2 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 1f71ebb..c67835f 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -40,7 +40,7 @@
#ifdef CONFIG_CPU_IDLE
/*
- * The latencies/thresholds for various C states have
+ * The MPU latencies/thresholds for various C states have
* to be configured from the respective board files.
* These are some default values (which might not provide
* the best power savings) used on boards which do not
@@ -75,14 +75,14 @@ struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
+ struct clockdomain *clkdm)
{
clkdm_allow_idle(clkdm);
return 0;
}
static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
+ struct clockdomain *clkdm)
{
clkdm_deny_idle(clkdm);
return 0;
@@ -96,10 +96,13 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
+ *
+ * Note: this function does not check for any pending activity or dependency
+ * between power domains states, so the caller shall check the parameters
+ * correctness.
*/
static int omap3_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+ struct cpuidle_driver *drv, int index)
{
struct omap3_idle_statedata *cx =
cpuidle_get_statedata(&dev->states_usage[index]);
@@ -174,18 +177,23 @@ return_sleep_time:
* to the caller. Else, this function searches for a lower c-state which is
* still valid (as defined in omap3_power_states[]) and returns its index.
*
- * A state is valid if the 'valid' field is enabled and
- * if it satisfies the enable_off_mode condition.
+ * A state is valid if:
+ * . the 'valid' field is enabled,
+ * . it satisfies the enable_off_mode flag,
+ * . the next state for MPU and CORE power domains is not lower than the
+ * state programmed by the per-device PM QoS.
*/
static int next_valid_state(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+ struct cpuidle_driver *drv, int index)
{
struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
struct cpuidle_state *curr = &drv->states[index];
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ u32 mpu_pm_qos_next_state = mpu_pd->wkup_lat_next_state;
+ u32 core_pm_qos_next_state = core_pd->wkup_lat_next_state;
+
int next_index = -1;
if (enable_off_mode) {
@@ -202,7 +210,9 @@ static int next_valid_state(struct cpuidle_device *dev,
/* Check if current state is valid */
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ (cx->core_state >= core_deepest_state) &&
+ (cx->mpu_state >= mpu_pm_qos_next_state) &&
+ (cx->core_state >= core_pm_qos_next_state)) {
return index;
} else {
int idx = OMAP3_NUM_STATES - 1;
@@ -227,7 +237,9 @@ static int next_valid_state(struct cpuidle_device *dev,
cx = cpuidle_get_statedata(&dev->states_usage[idx]);
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ (cx->core_state >= core_deepest_state) &&
+ (cx->mpu_state >= mpu_pm_qos_next_state) &&
+ (cx->core_state >= core_pm_qos_next_state)) {
next_index = idx;
break;
}
@@ -248,12 +260,15 @@ static int next_valid_state(struct cpuidle_device *dev,
* @drv: cpuidle driver
* @index: array index of target state to be programmed
*
- * This function checks for any pending activity and then programs
- * the device to the specified or a safer state.
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ *
+ * This function checks for any pending activity or dependency between
+ * power domains states and then programs the device to the specified
+ * or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+ struct cpuidle_driver *drv, int index)
{
int new_state_idx;
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
@@ -275,19 +290,13 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
goto select_state;
}
- /*
- * FIXME: we currently manage device-specific idle states
- * for PER and CORE in combination with CPU-specific
- * idle states. This is wrong, and device-specific
- * idle management needs to be separated out into
- * its own code.
- */
+ new_state_idx = next_valid_state(dev, drv, index);
/*
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
- cx = cpuidle_get_statedata(&dev->states_usage[index]);
+ cx = cpuidle_get_statedata(&dev->states_usage[new_state_idx]);
core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -298,8 +307,6 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);
- new_state_idx = next_valid_state(dev, drv, index);
-
select_state:
ret = omap3_enter_idle(dev, drv, new_state_idx);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index b737b11..ab32465 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -44,9 +44,22 @@ static inline int omap4_opp_init(void)
* omap3_pm_init_cpuidle
*/
struct cpuidle_params {
- u32 exit_latency; /* exit_latency = sleep + wake-up latencies */
+ /*
+ * exit_latency = sleep + wake-up latencies of the MPU,
+ * which include the MPU itself and the peripherals needed
+ * for the MPU to execute instructions (e.g. main memory,
+ * caches, IRQ controller, MMU etc). Some of those peripherals
+ * can belong to other power domains than the MPU subsystem and so
+ * the corresponding latencies must be included in this figure.
+ */
+ u32 exit_latency;
+ /*
+ * target_residency: required amount of time in the C state
+ * to break even on energy cost
+ */
u32 target_residency;
- u8 valid; /* validates the C-state */
+ /* validates the C-state on the given board */
+ u8 valid;
};
#if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/6] OMAP3: update cpuidle latency and threshold figures
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
` (3 preceding siblings ...)
2011-12-14 14:51 ` [PATCH 4/6] OMAP3: cpuidle: next C-state decision depends on the PM QoS MPU and CORE constraints jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 6/6] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
2011-12-19 21:02 ` [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code Paul Walmsley
6 siblings, 0 replies; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
Update the data from the measurements performed at HW and SW levels.
Cf. http://www.omappedia.org/wiki/Power_Management_Device_Latencies_Measurement
for a detailed explanation on where are the numbers coming from.
ToDo:
- Measure the wake-up latencies for all power domains for OMAP3
- Correct some numbers when sys_clkreq and sys_offmode are supported
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/cpuidle34xx.c | 52 +++++++++++++++++++++++-------------
1 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index c67835f..3caa932 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -40,27 +40,41 @@
#ifdef CONFIG_CPU_IDLE
/*
- * The MPU latencies/thresholds for various C states have
- * to be configured from the respective board files.
- * These are some default values (which might not provide
- * the best power savings) used on boards which do not
- * pass these details from the board file.
+ * The MPU latency and threshold values for the C-states are the worst case
+ * values from the HW and SW, as described in details at
+ * http://www.omappedia.org/wiki/Power_Management_Device_Latencies_Measurement#cpuidle_results
+ *
+ * Measurements conditions and remarks:
+ * . the measurements have been performed at OPP50
+ * . the sys_offmode signal is not supported and so not used for the
+ * measurements. Instead the latency and threshold values for C9 are
+ * corrected with the value for Triton 2, which is 11.5ms
+ * . the sys_clkreq signal is not used and so a correction is needed - TBD
+ * . the sys_clkoff signal is supported, this value need to be corrected with
+ * the correct value of SYSCLK on/off timings (1ms for sysclk on, 2.5ms
+ * for sysclk off)
+ * . in order to force the cpuidle algorithm to chose the power efficient
+ * C-states (C1, C3, C5, C7) in preference, the other C-states have a
+ * threshold value equal to the next power efficient C-state
+ *
+ * The latency and threshold values can be overriden by data from the board
+ * files, using omap3_pm_init_cpuidle.
*/
static struct cpuidle_params cpuidle_params_table[] = {
- /* C1 */
- {2 + 2, 5, 1},
- /* C2 */
- {10 + 10, 30, 1},
- /* C3 */
- {50 + 50, 300, 1},
- /* C4 */
- {1500 + 1800, 4000, 1},
- /* C5 */
- {2500 + 7500, 12000, 1},
- /* C6 */
- {3000 + 8500, 15000, 1},
- /* C7 */
- {10000 + 30000, 300000, 1},
+ /* C1 . MPU WFI + Core active */
+ {73 + 78, 152, 1},
+ /* C2 . MPU WFI + Core inactive */
+ {165 + 88, 345, 1},
+ /* C3 . MPU CSWR + Core inactive */
+ {163 + 182, 345, 1},
+ /* C4 . MPU OFF + Core inactive */
+ {2852 + 605, 150000, 1},
+ /* C5 . MPU RET + Core RET */
+ {800 + 366, 2120, 1},
+ /* C6 . MPU OFF + Core RET */
+ {4080 + 801, 215000, 1},
+ /* C7 . MPU OFF + Core OFF */
+ {4300 + 13000, 215000, 1},
};
#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/6] OMAP3: powerdomain data: add wake-up latency figures
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
` (4 preceding siblings ...)
2011-12-14 14:51 ` [PATCH 5/6] OMAP3: update cpuidle latency and threshold figures jean.pihet at newoldbits.com
@ 2011-12-14 14:51 ` jean.pihet at newoldbits.com
2011-12-19 21:02 ` [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code Paul Walmsley
6 siblings, 0 replies; 14+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-12-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <j-pihet@ti.com>
Figures are added to the power domains structs for RET and OFF modes.
Note: the latency figures for MPU, PER, CORE, NEON have been obtained
from actual measurements.
The latency figures for the other power domains are preliminary and
shall be added.
Cf. http://www.omappedia.org/wiki/Power_Management_Device_Latencies_Measurement
for a detailed explanation on where are the numbers coming from.
Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-omap2/powerdomains3xxx_data.c | 83 +++++++++++++++++++++++++++
1 files changed, 83 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 8ef26da..63a3afd 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -31,6 +31,19 @@
/*
* Powerdomains
+ *
+ * The wakeup_lat values are derived from HW and SW measurements on
+ * the actual target. For more details cf.
+ * http://www.omappedia.org/wiki/Power_Management_Device_Latencies_Measurement#Results_for_individual_power_domains
+ *
+ * Note: the latency figures for MPU, PER, CORE, NEON have been obtained
+ * from actual measurements.
+ * The latency figures for the other power domains are preliminary and
+ * shall be added.
+ *
+ * Note: only the SW restore timing values are taken into account.
+ * The HW impact of the sys_clkreq and sys_offmode signals is not taken
+ * into account - TDB
*/
static struct powerdomain iva2_pwrdm = {
@@ -51,6 +64,13 @@ static struct powerdomain iva2_pwrdm = {
[2] = PWRSTS_OFF_ON,
[3] = PWRSTS_ON,
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1100,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 350,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "mpu_iva" },
};
@@ -67,6 +87,13 @@ static struct powerdomain mpu_3xxx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_OFF_ON,
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1830,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 121,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "mpu_iva" },
};
@@ -94,6 +121,13 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 3082,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 153,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -116,6 +150,13 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 3082,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 153,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -131,6 +172,13 @@ static struct powerdomain dss_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 70,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 20,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -152,6 +200,13 @@ static struct powerdomain sgx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -167,6 +222,13 @@ static struct powerdomain cam_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 850,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 35,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -182,6 +244,13 @@ static struct powerdomain per_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 671,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 31,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
@@ -196,6 +265,13 @@ static struct powerdomain neon_pwrdm = {
.prcm_offs = OMAP3430_NEON_MOD,
.pwrsts = PWRSTS_OFF_RET_ON,
.pwrsts_logic_ret = PWRSTS_RET,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 0,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 0,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "mpu_iva" },
};
@@ -218,6 +294,13 @@ static struct powerdomain usbhost_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 800,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 150,
+ [PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
.voltdm = { .name = "core" },
};
--
1.7.5.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
` (5 preceding siblings ...)
2011-12-14 14:51 ` [PATCH 6/6] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
@ 2011-12-19 21:02 ` Paul Walmsley
2012-01-16 19:57 ` Jean Pihet
6 siblings, 1 reply; 14+ messages in thread
From: Paul Walmsley @ 2011-12-19 21:02 UTC (permalink / raw)
To: linux-arm-kernel
Hi Jean
I'm really sorry it's taken me so long to do detailed review of these
patches for merging... anyway -
On Wed, 14 Dec 2011, jean.pihet at newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> . Implement the devices wake-up latency constraints using the global
> device PM QoS notification handler which applies the constraints to the
> underlying layer
> . Implement the low level code which controls the power domains next power
> states, through the hwmod and pwrdm layers
> . Add cpuidle and power domains wake-up latency figures for OMAP3, cf.
> comments in the code and [1] for the details on where the numbers
> are magically coming from
> . Implement the relation between the cpuidle and per-device PM QoS frameworks
> in the OMAP3 specific idle callbacks.
> The chosen C-state shall satisfy the following conditions:
> . the 'valid' field is enabled,
> . it satisfies the enable_off_mode flag,
> . the next state for MPU and CORE power domains is not lower than the
> state programmed by the per-device PM QoS.
I've been reviewing these closely. It looks to me that are some issues
that need to be resolved before all of them are mergeable.
One issue that I noticed in this series is that there are some locking
issues in patch 1. It looks to me that calls to
_pwrdm_wakeuplat_update_pwrst() can race with each other, since it's
called outside the lock?
Another issue is with the latency data, which we've discussed previously.
Before we merge the latency data in mainline, we need to ensure that we've
minimized the dependency of that data on other register settings, such as
the AUTOEXTCLKMODE bits or the external high-frequency oscillator
stabilization time. Otherwise any board vendor that ships devices based
on that data will need to redo it, which we'd like to avoid. I'll comment
more on this in replies to those data patches.
But there is a more fundamental issue that we need to deal with before we
should merge the low-level powerdomain portion of your patches -- an issue
that isn't directly related to your code. We should first switch over to
use functional powerstates throughout our PM code. Right now, we have
some code that tweaks powerdomain bits directly, and some code that calls
omap_set_pwrdm_state(). We should get rid of the former, I think, so that
there is one single code path that directly changes the low-level
powerdomain bits. Otherwise I think we run the risk of having one of our
code paths lose track of what the powerdomain settings are -- and that way
lies madness...
Anyway, I've got some experimental code to do this, but since it touches a
lot of our existing PM code, I'd like to have Kevin's review, testing, and
approval of it. (And yours too, ideally ;-) So what I'd like to do is to
repost your series with some changes, and with the functional powerstate
portion sorted out first. Would you be able to help test those for 3.4?
In the meantime, it looks to me like two of your patches are good to go in
the short term, with some tweaks - the omap_hwmod changes and the
dev_pm_qos callback changes. I'll repost those shortly and queue them up
for whenever Tony wants to pull them.
- Paul
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints
2011-12-14 14:51 ` [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet at newoldbits.com
@ 2011-12-19 21:11 ` Paul Walmsley
0 siblings, 0 replies; 14+ messages in thread
From: Paul Walmsley @ 2011-12-19 21:11 UTC (permalink / raw)
To: linux-arm-kernel
Hi
On Wed, 14 Dec 2011, jean.pihet at newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> The OMAP PM code implements a handler for the per-device PM QoS framework.
> The handler queries the omap_hwmod layer in order to manage the power domains
> wake-up latency constraints. Hwmod retrieves the correct power domain
> and if it exists it calls the corresponding power domain function.
>
> Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
> latency constraints on MPU, CORE and PER.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> Reviewed-by: Kevin Hilman <khilman@ti.com>
I've modified this patch to split the omap_hwmod constraint functions into
a set-constraint function and a remove-constraint function. This removes
the dependency on the use of a magic value to indicate constraint removal.
It also removes the dependency on the Linux device PM layer's magic value,
which is not really related to this code.
Since the underlying powerdomain code isn't ready yet for the reasons
described in
http://marc.info/?l=linux-omap&m=132432863401849&w=2
those calls have been removed from this patch. They'll be added back in a
later series.
- Paul
From: Jean Pihet <j-pihet@ti.com>
Date: Sun, 18 Dec 2011 16:42:07 -0700
Subject: [PATCH] ARM: OMAP2+: hwmod: manage the wake-up latency constraints
The OMAP PM code implements a handler for the per-device PM QoS framework.
The handler queries the omap_hwmod layer in order to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: cleaned some documentation; split set/remove constraint
functions; modified to return -EINVAL until underlying code is ready]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 54 +++++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 5 ++
2 files changed, 58 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 207a2ff..f28cad2 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -143,6 +143,7 @@
#include "powerdomain.h"
#include <plat/clock.h>
#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include <plat/prcm.h>
#include "cm2xxx_3xxx.h"
@@ -2616,10 +2617,61 @@ ohsps_unlock:
}
/**
+ * omap_hwmod_set_wakeuplat_constraint - set/release a wake-up latency
+ * constraint
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Sets a wakeup latency contraint. (To remove a wakeup latency
+ * constraint, call omap_hwmod_remove_wakeuplat_constraint()).
+ * Returns the return value from pwrdm_wakeuplat_remove_constraint(),
+ * or -EINVAL in case of invalid parameters.
+ */
+int omap_hwmod_set_wakeuplat_constraint(struct omap_hwmod *oh, void *cookie,
+ long min_latency)
+{
+ struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * XXX Update to use pwrdm_wakeuplat_update_constraint() when
+ * that code is ready
+ */
+ return -EINVAL;
+}
+
+/**
+ * omap_hwmod_remove_wakeuplat_constraint - release a wake-up latency
+ * constraint
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ *
+ * Removes a wakeup latency contraint. Returns the return value from
+ * pwrdm_wakeuplat_update_constraint(), or -EINVAL in case of invalid
+ * parameters.
+ */
+int omap_hwmod_remove_wakeuplat_constraint(struct omap_hwmod *oh, void *cookie)
+{
+ struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * XXX Update to use pwrdm_wakeuplat_remove_constraint() when
+ * that code is ready
+ */
+ return -EINVAL;
+}
+
+/**
* omap_hwmod_get_context_loss_count - get lost context count
* @oh: struct omap_hwmod *
*
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
* count for this device.
*
* Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 8b372ed..ff60532 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -600,6 +600,11 @@ int omap_hwmod_for_each_by_class(const char *classname,
void *user);
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+
+int omap_hwmod_set_wakeuplat_constraint(struct omap_hwmod *oh, void *cookie,
+ long min_latency);
+int omap_hwmod_remove_wakeuplat_constraint(struct omap_hwmod *oh, void *cookie);
+
int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
--
1.7.7.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework
2011-12-14 14:51 ` [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework jean.pihet at newoldbits.com
@ 2011-12-19 21:12 ` Paul Walmsley
0 siblings, 0 replies; 14+ messages in thread
From: Paul Walmsley @ 2011-12-19 21:12 UTC (permalink / raw)
To: linux-arm-kernel
Hi
On Wed, 14 Dec 2011, jean.pihet at newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> Implement the devices wake-up latency constraints using the global
> device PM QoS notification handler which applies the constraints to the
> underlying layer by calling the corresponding function at hwmod level.
>
> Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
> latency constraints on MPU, CORE and PER.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> Reviewed-by: Kevin Hilman <khilman@ti.com>
I've modified this patch to work with omap_devices that contain multiple
hwmods, and to move the code to the mach-omap2/omap_device.c code, which
seems to make more sense. Since the hwmod set-constraint and
remove-constraint functions are now split, this code also must determine
which one to call.
- Paul
From: Jean Pihet <j-pihet@ti.com>
Date: Sun, 18 Dec 2011 16:42:07 -0700
Subject: [PATCH] ARM: OMAP: omap_device: register to the per-device PM QoS
framework
Implement the devices wake-up latency constraints using the global
device PM QoS notification handler which applies the constraints to the
underlying layer by calling the corresponding function at hwmod level.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: modified to work with omap_devices with large numbers of
hwmods; moved code to mach-omap2/omap_device.c; added documentation; use
notifier return codes]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/plat-omap/omap_device.c | 74 ++++++++++++++++++++++++++++++++++++++
1 files changed, 74 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index e8d9869..b2c18b7 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -2,6 +2,7 @@
* omap_device implementation
*
* Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
* Paul Walmsley, Kevin Hilman
*
* Developed in collaboration with (alphabetical order): Benoit
@@ -88,6 +89,7 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/notifier.h>
+#include <linux/pm_qos.h>
#include <plat/omap_device.h>
#include <plat/omap_hwmod.h>
@@ -409,6 +411,67 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
return NOTIFY_DONE;
}
+/**
+ * _omap_device_pm_qos_handler - interface to the per-device PM QoS framework
+ * @nb: pointer to omap_device_pm_qos_nb (not used)
+ * @new_value: new maximum wakeup latency constraint for @req->dev (in ?s)
+ * @req: struct dev_pm_qos_request * passed by the Linux PM QoS code
+ *
+ * Called by the Linux core device PM QoS code to alter the maximum
+ * wakeup latency constraint on a device. If the underlying device is
+ * an omap_device, then this code will pass the constraint on to the
+ * underlying hwmods. Returns -EINVAL if this code can't handle the
+ * constraint for some reason, or passes along the return code from the
+ * hwmod wakeup latency constraint functions.
+ */
+static int _omap_device_pm_qos_handler(struct notifier_block *nb,
+ unsigned long new_value,
+ void *req)
+{
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request *dev_pm_qos_req = req;
+ int ret = NOTIFY_OK;
+ int r, i;
+
+ pr_debug("OMAP PM constraints: req at 0x%p, new_value=%lu\n",
+ req, new_value);
+
+ /* Look for the platform device for the constraint target device */
+ pdev = to_platform_device(dev_pm_qos_req->dev);
+
+ /* Try to catch non platform devices */
+ if (pdev->name == NULL) {
+ pr_err("%s: Error: platform device for device %s not valid\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return NOTIFY_DONE;
+ }
+
+ /* Find the associated omap_device for dev */
+ od = to_omap_device(pdev);
+ if (od == NULL) {
+ pr_err("%s: Error: no omap_device for device %s\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return NOTIFY_DONE;
+ }
+
+ pr_debug("OMAP PM constraints: req at 0x%p, dev=0x%p, new_value=%lu\n",
+ req, dev_pm_qos_req->dev, new_value);
+
+ for (i = 0; i < od->hwmods_cnt; i++) {
+ oh = od->hwmods[i];
+ if (new_value == PM_QOS_DEV_LAT_DEFAULT_VALUE)
+ r = omap_hwmod_remove_wakeuplat_constraint(oh, dev_pm_qos_req);
+ else
+ r = omap_hwmod_set_wakeuplat_constraint(oh, dev_pm_qos_req, new_value);
+
+ if (!r)
+ ret = NOTIFY_BAD;
+ }
+
+ return ret;
+}
/* Public functions for use by core code */
@@ -1135,13 +1198,24 @@ struct device omap_device_parent = {
.parent = &platform_bus,
};
+static struct notifier_block omap_device_pm_qos_nb = {
+ .notifier_call = _omap_device_pm_qos_handler,
+};
+
static struct notifier_block platform_nb = {
.notifier_call = _omap_device_notifier_call,
};
static int __init omap_device_init(void)
{
+ int ret;
+
bus_register_notifier(&platform_bus_type, &platform_nb);
+
+ ret = dev_pm_qos_add_global_notifier(&omap_device_pm_qos_nb);
+ if (!ret)
+ pr_err("omap_device: cannot add global notifier for dev PM QoS\n");
+
return device_register(&omap_device_parent);
}
core_initcall(omap_device_init);
--
1.7.7.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
2011-12-19 21:02 ` [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code Paul Walmsley
@ 2012-01-16 19:57 ` Jean Pihet
2012-01-16 20:04 ` Paul Walmsley
2012-01-16 20:08 ` Paul Walmsley
0 siblings, 2 replies; 14+ messages in thread
From: Jean Pihet @ 2012-01-16 19:57 UTC (permalink / raw)
To: linux-arm-kernel
Paul, Kevin,
On Mon, Dec 19, 2011 at 10:02 PM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi Jean
>
> I'm really sorry it's taken me so long to do detailed review of these
> patches for merging... anyway -
>
> On Wed, 14 Dec 2011, jean.pihet at newoldbits.com wrote:
>
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> . Implement the devices wake-up latency constraints using the global
>> ? device PM QoS notification handler which applies the constraints to the
>> ? underlying layer
>> . Implement the low level code which controls the power domains next power
>> ? states, through the hwmod and pwrdm layers
>> . Add cpuidle and power domains wake-up latency figures for OMAP3, cf.
>> ? comments in the code and [1] for the details on where the numbers
>> ? are magically coming from
>> . Implement the relation between the cpuidle and per-device PM QoS frameworks
>> ? in the OMAP3 specific idle callbacks.
>> ? The chosen C-state shall satisfy the following conditions:
>> ? ?. the 'valid' field is enabled,
>> ? ?. it satisfies the enable_off_mode flag,
>> ? ?. the next state for MPU and CORE power domains is not lower than the
>> ? ? ?state programmed by the per-device PM QoS.
>
> I've been reviewing these closely. ?It looks to me that are some issues
> that need to be resolved before all of them are mergeable.
>
> One issue that I noticed in this series is that there are some locking
> issues in patch 1. ?It looks to me that calls to
> _pwrdm_wakeuplat_update_pwrst() can race with each other, since it's
> called outside the lock?
I fixed this by moving the lock so that it includes the update of the
next power state.
Speaking of the locking, currently a spinlock is used and it could be
replaced by a more efficient mutex. This is ok at the condition that
this code is not called from interrupt context?
Kevin,
Do you know if the per-device constraint code can be called from
interrupt context?
>
...
>
>
> - Paul
Jean
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
2012-01-16 19:57 ` Jean Pihet
@ 2012-01-16 20:04 ` Paul Walmsley
2012-01-16 20:22 ` Jean Pihet
2012-01-16 20:08 ` Paul Walmsley
1 sibling, 1 reply; 14+ messages in thread
From: Paul Walmsley @ 2012-01-16 20:04 UTC (permalink / raw)
To: linux-arm-kernel
Hi
On Mon, 16 Jan 2012, Jean Pihet wrote:
> Speaking of the locking, currently a spinlock is used and it could be
> replaced by a more efficient mutex. This is ok at the condition that
> this code is not called from interrupt context?
>
> Kevin,
> Do you know if the per-device constraint code can be called from
> interrupt context?
It can't be. It uses a mutex itself. So a mutex is what we want. Take a
look at drivers/base/power/qos.c:dev_pm_qos_update_request() (included
below)
- Paul
/**
* dev_pm_qos_update_request - modifies an existing qos request
* @req : handle to list element holding a dev_pm_qos request to use
* @new_value: defines the qos request
*
* Updates an existing dev PM qos request along with updating the
* target value.
*
* Attempts are made to make this code callable on hot code paths.
*
* Returns 1 if the aggregated constraint value has changed,
* 0 if the aggregated constraint value has not changed,
* -EINVAL in case of wrong parameters, -ENODEV if the device has been
* removed from the system
*/
int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
s32 new_value)
{
int ret = 0;
if (!req) /*guard against callers passing in null */
return -EINVAL;
if (WARN(!dev_pm_qos_request_active(req),
"%s() called for unknown object\n", __func__))
return -EINVAL;
mutex_lock(&dev_pm_qos_mtx);
if (req->dev->power.constraints) {
if (new_value != req->node.prio)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
new_value);
} else {
/* Return if the device has been removed */
ret = -ENODEV;
}
mutex_unlock(&dev_pm_qos_mtx);
return ret;
}
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
2012-01-16 19:57 ` Jean Pihet
2012-01-16 20:04 ` Paul Walmsley
@ 2012-01-16 20:08 ` Paul Walmsley
1 sibling, 0 replies; 14+ messages in thread
From: Paul Walmsley @ 2012-01-16 20:08 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, 16 Jan 2012, Jean Pihet wrote:
> Speaking of the locking, currently a spinlock is used and it could be
> replaced by a more efficient mutex.
Just a minor observation. It's not so much that the mutex is more
efficient. It's just that mutexes allow interrupt processing on that CPU
while they are held, unlike spinlocks. So the use of spinlocks can
increase the latency to service an interrupt request. We'd like to keep
that latency as low as possible.
- Paul
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code
2012-01-16 20:04 ` Paul Walmsley
@ 2012-01-16 20:22 ` Jean Pihet
0 siblings, 0 replies; 14+ messages in thread
From: Jean Pihet @ 2012-01-16 20:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
On Mon, Jan 16, 2012 at 9:04 PM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi
>
> On Mon, 16 Jan 2012, Jean Pihet wrote:
>
>> Speaking of the locking, currently a spinlock is used and it could be
>> replaced by a more efficient mutex. This is ok at the condition that
>> this code is not called from interrupt context?
>>
>> Kevin,
>> Do you know if the per-device constraint code can be called from
>> interrupt context?
>
> It can't be. ?It uses a mutex itself. ?So a mutex is what we want. ?Take a
> look at drivers/base/power/qos.c:dev_pm_qos_update_request() (included
> below)
Ok thanks for checking, I should have done it before asking ;-|
Jean
>
>
> - Paul
>
>
> /**
> ?* dev_pm_qos_update_request - modifies an existing qos request
> ?* @req : handle to list element holding a dev_pm_qos request to use
> ?* @new_value: defines the qos request
> ?*
> ?* Updates an existing dev PM qos request along with updating the
> ?* target value.
> ?*
> ?* Attempts are made to make this code callable on hot code paths.
> ?*
> ?* Returns 1 if the aggregated constraint value has changed,
> ?* 0 if the aggregated constraint value has not changed,
> ?* -EINVAL in case of wrong parameters, -ENODEV if the device has been
> ?* removed from the system
> ?*/
> int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?s32 new_value)
> {
> ? ? ? ?int ret = 0;
>
> ? ? ? ?if (!req) /*guard against callers passing in null */
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> ? ? ? ?if (WARN(!dev_pm_qos_request_active(req),
> ? ? ? ? ? ? ? ? "%s() called for unknown object\n", __func__))
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> ? ? ? ?mutex_lock(&dev_pm_qos_mtx);
>
> ? ? ? ?if (req->dev->power.constraints) {
> ? ? ? ? ? ? ? ?if (new_value != req->node.prio)
> ? ? ? ? ? ? ? ? ? ? ? ?ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new_value);
> ? ? ? ?} else {
> ? ? ? ? ? ? ? ?/* Return if the device has been removed */
> ? ? ? ? ? ? ? ?ret = -ENODEV;
> ? ? ? ?}
>
> ? ? ? ?mutex_unlock(&dev_pm_qos_mtx);
> ? ? ? ?return ret;
> }
>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-01-16 20:22 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-14 14:51 [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 1/6] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 2/6] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet at newoldbits.com
2011-12-19 21:11 ` Paul Walmsley
2011-12-14 14:51 ` [PATCH 3/6] OMAP: PM: register to the per-device PM QoS framework jean.pihet at newoldbits.com
2011-12-19 21:12 ` Paul Walmsley
2011-12-14 14:51 ` [PATCH 4/6] OMAP3: cpuidle: next C-state decision depends on the PM QoS MPU and CORE constraints jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 5/6] OMAP3: update cpuidle latency and threshold figures jean.pihet at newoldbits.com
2011-12-14 14:51 ` [PATCH 6/6] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
2011-12-19 21:02 ` [PATCH v6 0/6] PM QoS: implement the OMAP low level constraints management code Paul Walmsley
2012-01-16 19:57 ` Jean Pihet
2012-01-16 20:04 ` Paul Walmsley
2012-01-16 20:22 ` Jean Pihet
2012-01-16 20:08 ` Paul Walmsley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).