* [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code
@ 2011-09-02 13:13 Jean Pihet
2011-09-02 13:13 ` [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints Jean Pihet
` (8 more replies)
0 siblings, 9 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
. create a PM layer plugin for per-device constraints, compiled under
CONFIG_OMAP_PM_CONSTRAINTS=y
. 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. [1]
for the details on where the numbers are coming from
. cpuidle is a CPU centric framework so it decides the MPU next power state
based on the MPU exit_latency and target_residency figures. The rest of
the power domains get their next power state programmed from the devices
PM QoS framework, via the devices wake-up latency constraints.
. convert the OMAP I2C driver to the PM QoS API for MPU latency constraints
ToDo:
1. validate the constraints framework on OMAP4 HW (done on OMAP3)
2. 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
Based on the pm-qos branch of the linux-pm git tree (3.1.0-rc3), 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/rafael/linux-pm.git
Jean Pihet (8):
OMAP: convert I2C driver to PM QoS for latency constraints
OMAP: PM: create a PM layer plugin for per-device constraints
OMAP2+: powerdomain: control power domains next state
OMAP3: powerdomain data: add wake-up latency figures
OMAP2+: omap_hwmod: manage the wake-up latency constraints
OMAP: PM CONSTRAINTS: implement the devices wake-up latency
constraints
OMAP2+: cpuidle only influences the MPU state
OMAP3: update cpuidle latency and threshold figures
arch/arm/mach-omap2/cpuidle34xx.c | 56 ++---
arch/arm/mach-omap2/omap_hwmod.c | 26 ++-
arch/arm/mach-omap2/pm.h | 17 ++-
arch/arm/mach-omap2/powerdomain.c | 190 ++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 33 +++-
arch/arm/mach-omap2/powerdomains3xxx_data.c | 78 ++++++
arch/arm/plat-omap/Kconfig | 7 +
arch/arm/plat-omap/Makefile | 1 +
arch/arm/plat-omap/i2c.c | 20 --
arch/arm/plat-omap/include/plat/omap-pm.h | 128 ----------
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +
arch/arm/plat-omap/omap-pm-constraints.c | 350 ++++++++++++++++++++++++++
arch/arm/plat-omap/omap-pm-noop.c | 89 -------
drivers/i2c/busses/i2c-omap.c | 31 ++-
14 files changed, 737 insertions(+), 291 deletions(-)
create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
--
1.7.4.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-15 22:46 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 2/8] OMAP: PM: create a PM layer plugin for per-device constraints Jean Pihet
` (7 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
Convert the driver from the outdated omap_pm_set_max_mpu_wakeup_lat
API to the new PM QoS API.
Since the constraint is on the MPU subsystem, use the PM_QOS_CPU_DMA_LATENCY
class of PM QoS. The resulting MPU constraints are used by cpuidle to
decide the next power state of the MPU subsystem.
Currently only OMAP3 is placing constraints on the MPU.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
arch/arm/plat-omap/i2c.c | 20 --------------------
drivers/i2c/busses/i2c-omap.c | 31 ++++++++++++++++++-------------
2 files changed, 18 insertions(+), 33 deletions(-)
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 3341ca4..e1e2502 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -34,7 +34,6 @@
#include <mach/irqs.h>
#include <plat/mux.h>
#include <plat/i2c.h>
-#include <plat/omap-pm.h>
#include <plat/omap_device.h>
#define OMAP_I2C_SIZE 0x3f
@@ -113,16 +112,6 @@ static inline int omap1_i2c_add_bus(int bus_id)
#ifdef CONFIG_ARCH_OMAP2PLUS
-/*
- * XXX This function is a temporary compatibility wrapper - only
- * needed until the I2C driver can be converted to call
- * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
- */
-static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
-{
- omap_pm_set_max_mpu_wakeup_lat(dev, t);
-}
-
static struct omap_device_pm_latency omap_i2c_latency[] = {
[0] = {
.deactivate_func = omap_device_idle_hwmods,
@@ -151,15 +140,6 @@ static inline int omap2_i2c_add_bus(int bus_id)
}
pdata = &i2c_pdata[bus_id - 1];
- /*
- * When waiting for completion of a i2c transfer, we need to
- * set a wake up latency constraint for the MPU. This is to
- * ensure quick enough wakeup from idle, when transfer
- * completes.
- * Only omap3 has support for constraints
- */
- if (cpu_is_omap34xx())
- pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
od = omap_device_build(name, bus_id, oh, pdata,
sizeof(struct omap_i2c_bus_platform_data),
omap_i2c_latency, ARRAY_SIZE(omap_i2c_latency), 0);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 1a766cf..1c762ba 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -40,6 +40,7 @@
#include <linux/slab.h>
#include <linux/i2c-omap.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
/* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20
@@ -179,8 +180,7 @@ struct omap_i2c_dev {
struct completion cmd_complete;
struct resource *ioarea;
u32 latency; /* maximum mpu wkup latency */
- void (*set_mpu_wkup_lat)(struct device *dev,
- long latency);
+ struct pm_qos_request pm_qos_request;
u32 speed; /* Speed of bus in Khz */
u16 cmd_err;
u8 *buf;
@@ -648,8 +648,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (r < 0)
goto out;
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+ /*
+ * When waiting for completion of a i2c transfer, we need to
+ * set a wake up latency constraint for the MPU. This is to
+ * ensure quick enough wakeup from idle, when transfer
+ * completes.
+ * Used on OMAP3 Only
+ */
+ if (cpu_is_omap34xx())
+ pm_qos_add_request(&dev->pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
+ dev->latency);
for (i = 0; i < num; i++) {
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -657,8 +665,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
break;
}
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, -1);
+ if (cpu_is_omap34xx())
+ pm_qos_remove_request(&dev->pm_qos_request);
if (r == 0)
r = num;
@@ -1007,13 +1015,10 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_release_region;
}
- if (pdata != NULL) {
+ if (pdata != NULL)
speed = pdata->clkrate;
- dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
- } else {
+ else
speed = 100; /* Default speed */
- dev->set_mpu_wkup_lat = NULL;
- }
dev->speed = speed;
dev->idle = 1;
@@ -1066,8 +1071,8 @@ omap_i2c_probe(struct platform_device *pdev)
dev->fifo_size = (dev->fifo_size / 2);
dev->b_hw = 1; /* Enable hardware fixes */
}
- /* calculate wakeup latency constraint for MPU */
- if (dev->set_mpu_wkup_lat != NULL)
+ /* calculate wakeup latency constraint */
+ if (cpu_is_omap34xx())
dev->latency = (1000000 * dev->fifo_size) /
(1000 * speed / 8);
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/8] OMAP: PM: create a PM layer plugin for per-device constraints
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
2011-09-02 13:13 ` [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-02 13:13 ` [PATCH 3/8] OMAP2+: powerdomain: control power domains next state Jean Pihet
` (6 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
Created arch/arm/plat-omap/omap-pm-constraints.c file from
arch/arm/plat-omap/omap-pm-noop.c and the associated Kconfig option
OMAP_PM_CONSTRAINTS.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
arch/arm/plat-omap/Kconfig | 7 +
arch/arm/plat-omap/Makefile | 1 +
arch/arm/plat-omap/omap-pm-constraints.c | 363 ++++++++++++++++++++++++++++++
3 files changed, 371 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index bb8f4a6..3ee47a1 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -215,6 +215,13 @@ choice
config OMAP_PM_NOOP
bool "No-op/debug PM layer"
+config OMAP_PM_CONSTRAINTS
+ depends on PM
+ bool "Per device constraints"
+ help
+ Select this option to enable the PM layer plugin for
+ the per-device constraints support
+
endchoice
endmenu
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f0233e6..f2e09f1 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -32,3 +32,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+obj-$(CONFIG_OMAP_PM_CONSTRAINTS) += omap-pm-constraints.o
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
new file mode 100644
index 0000000..c8b4e4c
--- /dev/null
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -0,0 +1,363 @@
+/*
+ * omap-pm.c - OMAP power management interface
+ *
+ * This code implements the OMAP power management interface to
+ * drivers, CPUIdle, CPUFreq, and DSP Bridge.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * Interface developed by (in alphabetical order):
+ * Karthik Dasu, Tony Lindgren, Jean Pihet, Rajendra Nayak, Sakari Poussa,
+ * Veeramanikandan Raju, Anand Sawant, Igor Stoppa, Paul Walmsley,
+ * Richard Woodruff
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* Interface documentation is in mach/omap-pm.h */
+#include <plat/omap-pm.h>
+#include <plat/omap_device.h>
+
+static bool off_mode_enabled;
+static u32 dummy_context_loss_counter;
+
+/*
+ * Device-driver-originated constraints (via board-*.c files)
+ */
+
+int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+{
+ if (!dev || t < -1) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ };
+
+ if (t == -1)
+ pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
+ "dev %s\n", dev_name(dev));
+ else
+ pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
+ "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+ /*
+ * For current Linux, this needs to map the MPU to a
+ * powerdomain, then go through the list of current max lat
+ * constraints on the MPU and find the smallest. If
+ * the latency constraint has changed, the code should
+ * recompute the state to enter for the next powerdomain
+ * state.
+ *
+ * TI CDP code can call constraint_set here.
+ */
+
+ return 0;
+}
+
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+{
+ if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+ agent_id != OCP_TARGET_AGENT)) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ };
+
+ if (r == 0)
+ pr_debug("OMAP PM: remove min bus tput constraint: "
+ "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+ else
+ pr_debug("OMAP PM: add min bus tput constraint: "
+ "dev %s for agent_id %d: rate %ld KiB\n",
+ dev_name(dev), agent_id, r);
+
+ /*
+ * This code should model the interconnect and compute the
+ * required clock frequency, convert that to a VDD2 OPP ID, then
+ * set the VDD2 OPP appropriately.
+ *
+ * TI CDP code can call constraint_set here on the VDD2 OPP.
+ */
+
+ return 0;
+}
+
+int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
+ long t)
+{
+ if (!req_dev || !dev || t < -1) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ };
+
+ if (t == -1)
+ pr_debug("OMAP PM: remove max device latency constraint: "
+ "dev %s\n", dev_name(dev));
+ else
+ pr_debug("OMAP PM: add max device latency constraint: "
+ "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+ /*
+ * For current Linux, this needs to map the device to a
+ * powerdomain, then go through the list of current max lat
+ * constraints on that powerdomain and find the smallest. If
+ * the latency constraint has changed, the code should
+ * recompute the state to enter for the next powerdomain
+ * state. Conceivably, this code should also determine
+ * whether to actually disable the device clocks or not,
+ * depending on how long it takes to re-enable the clocks.
+ *
+ * TI CDP code can call constraint_set here.
+ */
+
+ return 0;
+}
+
+int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+{
+ if (!dev || t < -1) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ };
+
+ if (t == -1)
+ pr_debug("OMAP PM: remove max DMA latency constraint: "
+ "dev %s\n", dev_name(dev));
+ else
+ pr_debug("OMAP PM: add max DMA latency constraint: "
+ "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+ /*
+ * For current Linux PM QOS params, this code should scan the
+ * list of maximum CPU and DMA latencies and select the
+ * smallest, then set cpu_dma_latency pm_qos_param
+ * accordingly.
+ *
+ * For future Linux PM QOS params, with separate CPU and DMA
+ * latency params, this code should just set the dma_latency param.
+ *
+ * TI CDP code can call constraint_set here.
+ */
+
+ return 0;
+}
+
+int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
+{
+ if (!dev || !c || r < 0) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ }
+
+ if (r == 0)
+ pr_debug("OMAP PM: remove min clk rate constraint: "
+ "dev %s\n", dev_name(dev));
+ else
+ pr_debug("OMAP PM: add min clk rate constraint: "
+ "dev %s, rate = %ld Hz\n", dev_name(dev), r);
+
+ /*
+ * Code in a real implementation should keep track of these
+ * constraints on the clock, and determine the highest minimum
+ * clock rate. It should iterate over each OPP and determine
+ * whether the OPP will result in a clock rate that would
+ * satisfy this constraint (and any other PM constraint in effect
+ * at that time). Once it finds the lowest-voltage OPP that
+ * meets those conditions, it should switch to it, or return
+ * an error if the code is not capable of doing so.
+ */
+
+ return 0;
+}
+
+/*
+ * DSP Bridge-specific constraints
+ */
+
+const struct omap_opp *omap_pm_dsp_get_opp_table(void)
+{
+ pr_debug("OMAP PM: DSP request for OPP table\n");
+
+ /*
+ * Return DSP frequency table here: The final item in the
+ * array should have .rate = .opp_id = 0.
+ */
+
+ return NULL;
+}
+
+void omap_pm_dsp_set_min_opp(u8 opp_id)
+{
+ if (opp_id == 0) {
+ WARN_ON(1);
+ return;
+ }
+
+ pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
+
+ /*
+ *
+ * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
+ * can just test to see which is higher, the CPU's desired OPP
+ * ID or the DSP's desired OPP ID, and use whichever is
+ * highest.
+ *
+ * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
+ * rate is keyed on MPU speed, not the OPP ID. So we need to
+ * map the OPP ID to the MPU speed for use with clk_set_rate()
+ * if it is higher than the current OPP clock rate.
+ *
+ */
+}
+
+
+u8 omap_pm_dsp_get_opp(void)
+{
+ pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
+
+ /*
+ * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
+ *
+ * CDP12.14+:
+ * Call clk_get_rate() on the OPP custom clock, map that to an
+ * OPP ID using the tables defined in board-*.c/chip-*.c files.
+ */
+
+ return 0;
+}
+
+/*
+ * CPUFreq-originated constraint
+ *
+ * In the future, this should be handled by custom OPP clocktype
+ * functions.
+ */
+
+struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void)
+{
+ pr_debug("OMAP PM: CPUFreq request for frequency table\n");
+
+ /*
+ * Return CPUFreq frequency table here: loop over
+ * all VDD1 clkrates, pull out the mpu_ck frequencies, build
+ * table
+ */
+
+ return NULL;
+}
+
+void omap_pm_cpu_set_freq(unsigned long f)
+{
+ if (f == 0) {
+ WARN_ON(1);
+ return;
+ }
+
+ pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+ f);
+
+ /*
+ * For l-o dev tree, determine whether MPU freq or DSP OPP id
+ * freq is higher. Find the OPP ID corresponding to the
+ * higher frequency. Call clk_round_rate() and clk_set_rate()
+ * on the OPP custom clock.
+ *
+ * CDP should just be able to set the VDD1 OPP clock rate here.
+ */
+}
+
+unsigned long omap_pm_cpu_get_freq(void)
+{
+ pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
+
+ /*
+ * Call clk_get_rate() on the mpu_ck.
+ */
+
+ return 0;
+}
+
+/**
+ * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been enabled.
+ */
+void omap_pm_enable_off_mode(void)
+{
+ off_mode_enabled = true;
+}
+
+/**
+ * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been disabled.
+ */
+void omap_pm_disable_off_mode(void)
+{
+ off_mode_enabled = false;
+}
+
+/*
+ * Device context loss tracking
+ */
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ u32 count;
+
+ if (WARN_ON(!dev))
+ return 0;
+
+ if (dev->parent == &omap_device_parent) {
+ count = omap_device_get_context_loss_count(pdev);
+ } else {
+ WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context "
+ "loss counter; device %s should be converted to "
+ "omap_device", dev_name(dev));
+ if (off_mode_enabled)
+ dummy_context_loss_counter++;
+ count = dummy_context_loss_counter;
+ }
+
+ pr_debug("OMAP PM: context loss count for dev %s = %d\n",
+ dev_name(dev), count);
+
+ return count;
+}
+
+#else
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+ return dummy_context_loss_counter;
+}
+
+#endif
+
+/* Should be called before clk framework init */
+int __init omap_pm_if_early_init(void)
+{
+ return 0;
+}
+
+/* Must be called after clock framework is initialized */
+int __init omap_pm_if_init(void)
+{
+ return 0;
+}
+
+void omap_pm_if_exit(void)
+{
+ /* Deallocate CPUFreq frequency table here */
+}
+
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/8] OMAP2+: powerdomain: control power domains next state
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
2011-09-02 13:13 ` [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints Jean Pihet
2011-09-02 13:13 ` [PATCH 2/8] OMAP: PM: create a PM layer plugin for per-device constraints Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-16 18:27 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 4/8] OMAP3: powerdomain data: add wake-up latency figures Jean Pihet
` (5 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
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>
---
arch/arm/mach-omap2/powerdomain.c | 190 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 33 ++++++-
2 files changed, 221 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..afa8153 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"
@@ -104,6 +106,11 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
for (i = 0; i < pwrdm->banks; i++)
pwrdm->ret_mem_off_counter[i] = 0;
+ /* Initialize the per-od wake-up constraints list and spinlock */
+ spin_lock_init(&pwrdm->wkup_lat_plist_lock);
+ plist_head_init(&pwrdm->wkup_lat_plist_head);
+
+ /* Initialize the pwrdm state */
pwrdm_wait_transition(pwrdm);
pwrdm->state = pwrdm_read_pwrst(pwrdm);
pwrdm->state_counter[pwrdm->state] = 1;
@@ -191,6 +198,77 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
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 upon success.
+ */
+static int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm,
+ long min_latency)
+{
+ int ret = 0, new_state = 0;
+
+ if (!pwrdm) {
+ WARN(1, "powerdomain: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Apply constraints to power domains by programming
+ * the pwrdm next power state.
+ */
+
+ /* Find 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 ||
+ 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;
+ }
+
+ 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 */
/**
@@ -930,6 +1008,118 @@ int pwrdm_post_transition(void)
return 0;
}
+/*
+ * 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 strongest constraint value for the given pwrdm by calling
+ * pwrdm_wakeuplat_update_pwrst.
+ *
+ * Returns 0 upon success or a negative value in case of error.
+ *
+ * The caller must check the validity of the parameters.
+ */
+int pwrdm_set_wkup_lat_constraint(struct powerdomain *pwrdm, void *cookie,
+ long min_latency)
+{
+ struct pwrdm_wkup_constraints_entry *user = NULL;
+ struct pwrdm_wkup_constraints_entry *tmp_user, *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);
+
+ /* 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))
+ goto exit_ok;
+
+ 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 */
+ ret = -EINVAL;
+ goto exit_error;
+ }
+
+ }
+
+exit_ok:
+ /* Find the strongest constraint from the list */
+ 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 */
+ pr_debug("powerdomain: %s: pwrdm %s, value=%ld\n",
+ __func__, pwrdm->name, value);
+ pwrdm_wakeuplat_update_pwrst(pwrdm, value);
+
+ return 0;
+
+exit_error:
+ spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+ 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 d23d979..f2b0ed7 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>
@@ -43,6 +45,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 */
@@ -93,7 +105,12 @@ 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
* @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
*/
struct powerdomain {
@@ -118,6 +135,15 @@ struct powerdomain {
s64 timer;
s64 state_timer[PWRDM_MAX_PWRSTS];
#endif
+ const u32 wakeup_lat[PWRDM_MAX_FUNC_PWRSTS];
+ struct plist_head wkup_lat_plist_head;
+ spinlock_t wkup_lat_plist_lock;
+};
+
+/* Linked list for the wake-up latency constraints */
+struct pwrdm_wkup_constraints_entry {
+ void *cookie;
+ struct plist_node node;
};
/**
@@ -207,6 +233,9 @@ 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);
u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/8] OMAP3: powerdomain data: add wake-up latency figures
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (2 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 3/8] OMAP2+: powerdomain: control power domains next state Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-02 13:13 ` [PATCH 5/8] OMAP2+: omap_hwmod: manage the wake-up latency constraints Jean Pihet
` (4 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
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.
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>
---
arch/arm/mach-omap2/powerdomains3xxx_data.c | 78 +++++++++++++++++++++++++++
1 files changed, 78 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 469a920..32922bb 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -31,6 +31,14 @@
/*
* Powerdomains
+ *
+ * The wakeup_lat values are derived from measurements on
+ * the actual target.
+ *
+ * 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.
*/
static struct powerdomain iva2_pwrdm = {
@@ -52,6 +60,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,
+ },
};
static struct powerdomain mpu_3xxx_pwrdm = {
@@ -68,6 +83,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,
+ },
};
/*
@@ -98,6 +120,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,
+ },
};
static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,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,
+ },
};
static struct powerdomain dss_pwrdm = {
@@ -136,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,
+ },
};
/*
@@ -157,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,
+ },
};
static struct powerdomain cam_pwrdm = {
@@ -172,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,
+ },
};
static struct powerdomain per_pwrdm = {
@@ -187,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,
+ },
};
static struct powerdomain emu_pwrdm = {
@@ -201,6 +265,13 @@ static struct powerdomain neon_pwrdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.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,
+ },
};
static struct powerdomain usbhost_pwrdm = {
@@ -223,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,
+ },
};
static struct powerdomain dpll1_pwrdm = {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 5/8] OMAP2+: omap_hwmod: manage the wake-up latency constraints
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (3 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 4/8] OMAP3: powerdomain data: add wake-up latency figures Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-02 13:13 ` [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices " Jean Pihet
` (3 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
Hwmod is queried from the OMAP_PM layer 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>
---
arch/arm/mach-omap2/omap_hwmod.c | 26 +++++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 ++
2 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..c6b1cc9 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"
@@ -2618,11 +2619,34 @@ ohsps_unlock:
return ret;
}
+/*
+ * 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.
+ */
+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 0e329ca..75e0e7a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -603,6 +603,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);
u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (4 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 5/8] OMAP2+: omap_hwmod: manage the wake-up latency constraints Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-15 23:47 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 7/8] OMAP2+: cpuidle only influences the MPU state Jean Pihet
` (2 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
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.
Note: the bus throughput function is implemented but currently is
a no-op. A new PM QoS class for the bus throughput needs to be
added.
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>
---
arch/arm/plat-omap/include/plat/omap-pm.h | 128 ---------------------
arch/arm/plat-omap/omap-pm-constraints.c | 173 +++++++++++++---------------
arch/arm/plat-omap/omap-pm-noop.c | 89 ---------------
3 files changed, 80 insertions(+), 310 deletions(-)
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 0840df8..d276082 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -62,136 +62,8 @@ void omap_pm_if_exit(void);
* Device-driver-originated constraints (via board-*.c files, platform_data)
*/
-
-/**
- * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency
- * @dev: struct device * requesting the constraint
- * @t: maximum MPU wakeup latency in microseconds
- *
- * Request that the maximum interrupt latency for the MPU to be no
- * greater than @t microseconds. "Interrupt latency" in this case is
- * defined as the elapsed time from the occurrence of a hardware or
- * timer interrupt to the time when the device driver's interrupt
- * service routine has been entered by the MPU.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the MPU powerdomain into, and
- * possibly the CORE powerdomain as well, since interrupt handling
- * code currently runs from SDRAM. Advanced PM or board*.c code may
- * also configure interrupt controller priorities, OCP bus priorities,
- * CPU speed(s), etc.
- *
- * This function will not affect device wakeup latency, e.g., time
- * elapsed from when a device driver enables a hardware device with
- * clk_enable(), to when the device is ready for register access or
- * other use. To control this device wakeup latency, use
- * omap_pm_set_max_dev_wakeup_lat()
- *
- * Multiple calls to omap_pm_set_max_mpu_wakeup_lat() will replace the
- * previous t value. To remove the latency target for the MPU, call
- * with t = -1.
- *
- * XXX This constraint will be deprecated soon in favor of the more
- * general omap_pm_set_max_dev_wakeup_lat()
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
-
-
-/**
- * omap_pm_set_min_bus_tput - set minimum bus throughput needed by device
- * @dev: struct device * requesting the constraint
- * @tbus_id: interconnect to operate on (OCP_{INITIATOR,TARGET}_AGENT)
- * @r: minimum throughput (in KiB/s)
- *
- * Request that the minimum data throughput on the OCP interconnect
- * attached to device @dev interconnect agent @tbus_id be no less
- * than @r KiB/s.
- *
- * It is expected that the OMAP PM or bus code will use this
- * information to set the interconnect clock to run at the lowest
- * possible speed that satisfies all current system users. The PM or
- * bus code will adjust the estimate based on its model of the bus, so
- * device driver authors should attempt to specify an accurate
- * quantity for their device use case, and let the PM or bus code
- * overestimate the numbers as necessary to handle request/response
- * latency, other competing users on the system, etc. On OMAP2/3, if
- * a driver requests a minimum L4 interconnect speed constraint, the
- * code will also need to add an minimum L3 interconnect speed
- * constraint,
- *
- * Multiple calls to omap_pm_set_min_bus_tput() will replace the
- * previous rate value for this device. To remove the interconnect
- * throughput restriction for this device, call with r = 0.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r);
-
-/**
- * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
- * @req_dev: struct device * requesting the constraint, or NULL if none
- * @dev: struct device * to set the constraint one
- * @t: maximum device wakeup latency in microseconds
- *
- * Request that the maximum amount of time necessary for a device @dev
- * to become accessible after its clocks are enabled should be no
- * greater than @t microseconds. Specifically, this represents the
- * time from when a device driver enables device clocks with
- * clk_enable(), to when the register reads and writes on the device
- * will succeed. This function should be called before clk_disable()
- * is called, since the power state transition decision may be made
- * during clk_disable().
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the powerdomain enclosing this
- * device into.
- *
- * Multiple calls to omap_pm_set_max_dev_wakeup_lat() will replace the
- * previous wakeup latency values for this device. To remove the
- * wakeup latency restriction for this device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t);
-
-
-/**
- * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency
- * @dev: struct device *
- * @t: maximum DMA transfer start latency in microseconds
- *
- * Request that the maximum system DMA transfer start latency for this
- * device 'dev' should be no greater than 't' microseconds. "DMA
- * transfer start latency" here is defined as the elapsed time from
- * when a device (e.g., McBSP) requests that a system DMA transfer
- * start or continue, to the time at which data starts to flow into
- * that device from the system DMA controller.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the CORE powerdomain into.
- *
- * Since system DMA transfers may not involve the MPU, this function
- * will not affect MPU wakeup latency. Use set_max_cpu_lat() to do
- * so. Similarly, this function will not affect device wakeup latency
- * -- use set_max_dev_wakeup_lat() to affect that.
- *
- * Multiple calls to set_max_sdma_lat() will replace the previous t
- * value for this device. To remove the maximum DMA latency for this
- * device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_sdma_lat(struct device *dev, long t);
-
-
/**
* omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
* @dev: struct device * requesting the constraint
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
index c8b4e4c..efec5df 100644
--- a/arch/arm/plat-omap/omap-pm-constraints.c
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -17,132 +17,112 @@
#undef DEBUG
#include <linux/init.h>
+#include <linux/notifier.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
/* Interface documentation is in mach/omap-pm.h */
#include <plat/omap-pm.h>
#include <plat/omap_device.h>
+#include <plat/common.h>
+#include <plat/omap_hwmod.h>
static bool off_mode_enabled;
static u32 dummy_context_loss_counter;
-/*
- * Device-driver-originated constraints (via board-*.c files)
- */
+static int _dev_pm_qos_wakeup_latency_handler(struct notifier_block *,
+ unsigned long, void *);
+static struct notifier_block _dev_pm_qos_wakeup_latency_notifier = {
+ .notifier_call = _dev_pm_qos_wakeup_latency_handler,
+};
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+
+static int _apply_dev_pm_qos_constraint(void *req, unsigned long new_value)
{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request *dev_pm_qos_req = req;
- if (t == -1)
- pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
+ pr_debug("OMAP PM CONSTRAINTS: req@0x%p, new_value=%lu\n",
+ req, new_value);
- /*
- * For current Linux, this needs to map the MPU to a
- * powerdomain, then go through the list of current max lat
- * constraints on the MPU and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state.
- *
- * TI CDP code can call constraint_set here.
- */
+ /* Look for the platform device for the constraint target device */
+ pdev = to_platform_device(dev_pm_qos_req->dev);
- return 0;
-}
+ /* 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;
+ }
-int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
-{
- if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
- agent_id != OCP_TARGET_AGENT)) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ /* Find the associated omap_device for dev */
+ od = container_of(pdev, struct omap_device, pdev);
+ 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;
- };
+ }
- if (r == 0)
- pr_debug("OMAP PM: remove min bus tput constraint: "
- "dev %s for agent_id %d\n", dev_name(dev), agent_id);
- else
- pr_debug("OMAP PM: add min bus tput constraint: "
- "dev %s for agent_id %d: rate %ld KiB\n",
- dev_name(dev), agent_id, r);
+ /* Find the primary omap_hwmod for dev */
+ oh = od->hwmods[0];
- /*
- * This code should model the interconnect and compute the
- * required clock frequency, convert that to a VDD2 OPP ID, then
- * set the VDD2 OPP appropriately.
- *
- * TI CDP code can call constraint_set here on the VDD2 OPP.
- */
+ pr_debug("OMAP PM CONSTRAINTS: req@0x%p, dev=0x%p, new_value=%lu\n",
+ req, dev_pm_qos_req->dev, new_value);
- return 0;
+ /* Apply the constraint */
+ return omap_hwmod_set_wkup_lat_constraint(oh, dev_pm_qos_req,
+ new_value);
}
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t)
+/* PM QoS classes handlers */
+static int _dev_pm_qos_wakeup_latency_handler(struct notifier_block *nb,
+ unsigned long new_value,
+ void *req)
{
- if (!req_dev || !dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max device latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max device latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the device to a
- * powerdomain, then go through the list of current max lat
- * constraints on that powerdomain and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state. Conceivably, this code should also determine
- * whether to actually disable the device clocks or not,
- * depending on how long it takes to re-enable the clocks.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
+ return _apply_dev_pm_qos_constraint(req, new_value);
}
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+/*
+ * omap_pm_set_min_bus_tput - set/release bus throughput constraints
+ * ToDo: currently is a no-op, to be converted to a PM QoS handler
+ * for the TPUT class
+ */
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
{
- if (!dev || t < -1) {
+ long t;
+ struct device *req_dev = NULL;
+
+ if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+ agent_id != OCP_TARGET_AGENT)) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
};
- if (t == -1)
- pr_debug("OMAP PM: remove max DMA latency constraint: "
- "dev %s\n", dev_name(dev));
+ /*
+ * A value of r == 0 removes the constraint. Convert it to the
+ * generic _set_dev_constraint convention (-1 for constraint removal)
+ */
+ if (r == 0)
+ t = -1;
else
- pr_debug("OMAP PM: add max DMA latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
+ t = r;
/*
- * For current Linux PM QOS params, this code should scan the
- * list of maximum CPU and DMA latencies and select the
- * smallest, then set cpu_dma_latency pm_qos_param
- * accordingly.
- *
- * For future Linux PM QOS params, with separate CPU and DMA
- * latency params, this code should just set the dma_latency param.
- *
- * TI CDP code can call constraint_set here.
+ * Assign the device for L3 or L4 interconnect to req_dev,
+ * based on the value of agent_id
*/
+ switch (agent_id) {
+ case OCP_INITIATOR_AGENT:
+ req_dev = omap2_get_l3_device();
+ break;
+ case OCP_TARGET_AGENT:
+ /* Fixme: need the device for L4 interconnect */
+ break;
+ }
return 0;
}
@@ -350,10 +330,17 @@ int __init omap_pm_if_early_init(void)
return 0;
}
-/* Must be called after clock framework is initialized */
+/* Must be called after the clock framework is initialized */
int __init omap_pm_if_init(void)
{
- return 0;
+ int ret;
+
+ ret = dev_pm_qos_add_global_notifier(
+ &_dev_pm_qos_wakeup_latency_notifier);
+ if (ret)
+ WARN(1, KERN_ERR "Cannot add global notifier for dev PM QoS\n");
+
+ return ret;
}
void omap_pm_if_exit(void)
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index b0471bb2..8ad902f 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -32,35 +32,6 @@ static u32 dummy_context_loss_counter;
/*
* Device-driver-originated constraints (via board-*.c files)
*/
-
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
-{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the MPU to a
- * powerdomain, then go through the list of current max lat
- * constraints on the MPU and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
{
if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
@@ -88,66 +59,6 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
return 0;
}
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t)
-{
- if (!req_dev || !dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max device latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max device latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the device to a
- * powerdomain, then go through the list of current max lat
- * constraints on that powerdomain and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state. Conceivably, this code should also determine
- * whether to actually disable the device clocks or not,
- * depending on how long it takes to re-enable the clocks.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
-{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max DMA latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max DMA latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux PM QOS params, this code should scan the
- * list of maximum CPU and DMA latencies and select the
- * smallest, then set cpu_dma_latency pm_qos_param
- * accordingly.
- *
- * For future Linux PM QOS params, with separate CPU and DMA
- * latency params, this code should just set the dma_latency param.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
{
if (!dev || !c || r < 0) {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 7/8] OMAP2+: cpuidle only influences the MPU state
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (5 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices " Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-02 13:13 ` [PATCH 8/8] OMAP3: update cpuidle latency and threshold figures Jean Pihet
2011-09-15 8:57 ` [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
Since cpuidle is a CPU centric framework it decides the MPU
next power state based on the MPU exit_latency and target_residency
figures.
The rest of the power domains get their next power state programmed
from the devices PM QoS framework, via the devices wake-up latency
constraints.
Note: the exit_latency and target_residency figures of the MPU
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.
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>
---
arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++++++-------------------------
arch/arm/mach-omap2/pm.h | 17 +++++++++++++-
2 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..b43d1d2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -37,26 +37,26 @@
#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
* pass these details from the board file.
*/
static struct cpuidle_params cpuidle_params_table[] = {
- /* C1 */
+ /* C1 . MPU WFI + Core active */
{2 + 2, 5, 1},
- /* C2 */
+ /* C2 . MPU WFI + Core inactive */
{10 + 10, 30, 1},
- /* C3 */
+ /* C3 . MPU CSWR + Core inactive */
{50 + 50, 300, 1},
- /* C4 */
+ /* C4 . MPU OFF + Core inactive */
{1500 + 1800, 4000, 1},
- /* C5 */
+ /* C5 . MPU RET + Core RET */
{2500 + 7500, 12000, 1},
- /* C6 */
+ /* C6 . MPU OFF + Core RET */
{3000 + 8500, 15000, 1},
- /* C7 */
+ /* C7 . MPU OFF + Core OFF */
{10000 + 30000, 300000, 1},
};
#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
@@ -64,7 +64,6 @@ static struct cpuidle_params cpuidle_params_table[] = {
/* Mach specific information to be recorded in the C-state driver_data */
struct omap3_idle_statedata {
u32 mpu_state;
- u32 core_state;
u8 valid;
};
struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
@@ -98,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
{
struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
struct timespec ts_preidle, ts_postidle, ts_idle;
- u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+ u32 mpu_state = cx->mpu_state;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
@@ -107,7 +106,6 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
local_fiq_disable();
pwrdm_set_next_pwrst(mpu_pd, mpu_state);
- pwrdm_set_next_pwrst(core_pd, core_state);
if (omap_irq_pending() || need_resched())
goto return_sleep_time;
@@ -156,6 +154,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ u32 core_next_state = pwrdm_read_next_pwrst(core_pd);
if (enable_off_mode) {
mpu_deepest_state = PWRDM_POWER_OFF;
@@ -171,7 +170,7 @@ static struct cpuidle_state *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)) {
+ (core_next_state >= core_deepest_state)) {
return curr;
} else {
int idx = OMAP3_NUM_STATES - 1;
@@ -196,7 +195,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
cx = cpuidle_get_statedata(&dev->states[idx]);
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ (core_next_state >= core_deepest_state)) {
next = &dev->states[idx];
break;
}
@@ -242,19 +241,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
}
/*
- * 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.
- */
-
- /*
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
cx = cpuidle_get_statedata(state);
- core_next_state = cx->core_state;
+ core_next_state = pwrdm_read_next_pwrst(core_pd);
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
(core_next_state > PWRDM_POWER_RET))
@@ -346,32 +337,26 @@ int __init omap3_idle_init(void)
dev->safe_state = &dev->states[0];
cx->valid = 1; /* C1 is always valid */
cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
/* C2 . MPU WFI + Core inactive */
cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
/* C3 . MPU CSWR + Core inactive */
cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_ON;
/* C4 . MPU OFF + Core inactive */
cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_ON;
/* C5 . MPU RET + Core RET */
cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_RET;
/* C6 . MPU OFF + Core RET */
cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_RET;
/* C7 . MPU OFF + Core OFF */
cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
@@ -386,7 +371,6 @@ int __init omap3_idle_init(void)
__func__);
}
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_OFF;
dev->state_count = OMAP3_NUM_STATES;
if (cpuidle_register_device(dev)) {
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 4e166ad..aca3b6c 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -43,9 +43,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.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 8/8] OMAP3: update cpuidle latency and threshold figures
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (6 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 7/8] OMAP2+: cpuidle only influences the MPU state Jean Pihet
@ 2011-09-02 13:13 ` Jean Pihet
2011-09-15 8:57 ` [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-02 13:13 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
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 magically 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>
---
arch/arm/mach-omap2/cpuidle34xx.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index b43d1d2..3f37e89 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -45,19 +45,19 @@
*/
static struct cpuidle_params cpuidle_params_table[] = {
/* C1 . MPU WFI + Core active */
- {2 + 2, 5, 1},
+ {73 + 78, 152, 1},
/* C2 . MPU WFI + Core inactive */
- {10 + 10, 30, 1},
+ {165 + 88, 345, 1},
/* C3 . MPU CSWR + Core inactive */
- {50 + 50, 300, 1},
+ {163 + 182, 345, 1},
/* C4 . MPU OFF + Core inactive */
- {1500 + 1800, 4000, 1},
+ {2852 + 605, 150000, 1},
/* C5 . MPU RET + Core RET */
- {2500 + 7500, 12000, 1},
+ {800 + 366, 2120, 1},
/* C6 . MPU OFF + Core RET */
- {3000 + 8500, 15000, 1},
+ {4080 + 801, 215000, 1},
/* C7 . MPU OFF + Core OFF */
- {10000 + 30000, 300000, 1},
+ {4300 + 13000, 215000, 1},
};
#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
` (7 preceding siblings ...)
2011-09-02 13:13 ` [PATCH 8/8] OMAP3: update cpuidle latency and threshold figures Jean Pihet
@ 2011-09-15 8:57 ` Jean Pihet
8 siblings, 0 replies; 17+ messages in thread
From: Jean Pihet @ 2011-09-15 8:57 UTC (permalink / raw)
To: Kevin Hilman, Linux PM mailing list, linux-omap,
Rafael J. Wysocki, Paul Walmsley
Cc: Jean Pihet
Paul, Rafael, Kevin,
Ping on this patch set.
IIUC the intention is to have this series merged in 3.2, is that correct?
Regards,
Jean
On Fri, Sep 2, 2011 at 3:13 PM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> . create a PM layer plugin for per-device constraints, compiled under
> CONFIG_OMAP_PM_CONSTRAINTS=y
> . 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. [1]
> for the details on where the numbers are coming from
> . cpuidle is a CPU centric framework so it decides the MPU next power state
> based on the MPU exit_latency and target_residency figures. The rest of
> the power domains get their next power state programmed from the devices
> PM QoS framework, via the devices wake-up latency constraints.
> . convert the OMAP I2C driver to the PM QoS API for MPU latency constraints
>
> ToDo:
> 1. validate the constraints framework on OMAP4 HW (done on OMAP3)
> 2. 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
>
>
> Based on the pm-qos branch of the linux-pm git tree (3.1.0-rc3), 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/rafael/linux-pm.git
>
>
> Jean Pihet (8):
> OMAP: convert I2C driver to PM QoS for latency constraints
> OMAP: PM: create a PM layer plugin for per-device constraints
> OMAP2+: powerdomain: control power domains next state
> OMAP3: powerdomain data: add wake-up latency figures
> OMAP2+: omap_hwmod: manage the wake-up latency constraints
> OMAP: PM CONSTRAINTS: implement the devices wake-up latency
> constraints
> OMAP2+: cpuidle only influences the MPU state
> OMAP3: update cpuidle latency and threshold figures
>
> arch/arm/mach-omap2/cpuidle34xx.c | 56 ++---
> arch/arm/mach-omap2/omap_hwmod.c | 26 ++-
> arch/arm/mach-omap2/pm.h | 17 ++-
> arch/arm/mach-omap2/powerdomain.c | 190 ++++++++++++++
> arch/arm/mach-omap2/powerdomain.h | 33 +++-
> arch/arm/mach-omap2/powerdomains3xxx_data.c | 78 ++++++
> arch/arm/plat-omap/Kconfig | 7 +
> arch/arm/plat-omap/Makefile | 1 +
> arch/arm/plat-omap/i2c.c | 20 --
> arch/arm/plat-omap/include/plat/omap-pm.h | 128 ----------
> arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +
> arch/arm/plat-omap/omap-pm-constraints.c | 350 ++++++++++++++++++++++++++
> arch/arm/plat-omap/omap-pm-noop.c | 89 -------
> drivers/i2c/busses/i2c-omap.c | 31 ++-
> 14 files changed, 737 insertions(+), 291 deletions(-)
> create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
>
> --
> 1.7.4.1
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints
2011-09-02 13:13 ` [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints Jean Pihet
@ 2011-09-15 22:46 ` Kevin Hilman
2011-09-16 15:39 ` Jean Pihet
0 siblings, 1 reply; 17+ messages in thread
From: Kevin Hilman @ 2011-09-15 22:46 UTC (permalink / raw)
To: Jean Pihet
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Hi Jean,
Jean Pihet <jean.pihet@newoldbits.com> writes:
> Convert the driver from the outdated omap_pm_set_max_mpu_wakeup_lat
> API to the new PM QoS API.
> Since the constraint is on the MPU subsystem, use the PM_QOS_CPU_DMA_LATENCY
> class of PM QoS. The resulting MPU constraints are used by cpuidle to
> decide the next power state of the MPU subsystem.
>
> Currently only OMAP3 is placing constraints on the MPU.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
[...]
> @@ -648,8 +648,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
> if (r < 0)
> goto out;
>
> - if (dev->set_mpu_wkup_lat != NULL)
> - dev->set_mpu_wkup_lat(dev->dev, dev->latency);
> + /*
> + * When waiting for completion of a i2c transfer, we need to
> + * set a wake up latency constraint for the MPU. This is to
> + * ensure quick enough wakeup from idle, when transfer
> + * completes.
> + * Used on OMAP3 Only
> + */
> + if (cpu_is_omap34xx())
We don't want any cpu_is_* checking in drivers.
If this is only done on certain SoCs, then a flag should be passed from
device init code via pdata.
That being said, I don't see why this shouldn't be set for all SoCs
since it's using the FIFO size to determine the latency.
Kevin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
2011-09-02 13:13 ` [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices " Jean Pihet
@ 2011-09-15 23:47 ` Kevin Hilman
2011-09-16 15:43 ` Jean Pihet
0 siblings, 1 reply; 17+ messages in thread
From: Kevin Hilman @ 2011-09-15 23:47 UTC (permalink / raw)
To: Jean Pihet
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Jean Pihet <jean.pihet@newoldbits.com> writes:
> 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.
>
> Note: the bus throughput function is implemented but currently is
> a no-op. A new PM QoS class for the bus throughput needs to be
> added.
>
> 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>
This patch does 2 things.
1) removes the MPU lat stuff from the OMAP PM layer (since it's now
available in a generic form
2) implements device wake-up latency constraints
This should be broken up into two parts.
Also, this patch seems to remove a bunch of stuff that was just added in
patch 2/8. Probably best to create the new OMAP PM layer after remving
the unused stuff.
It think the code using the new per-device PM QoS API should also live
outside the OMAP PM layer, since it's not related, and we want to get
rid of the OMAP PM layer eventually.
Speaking of which..., the more I think about it, the more I think we
should take this opportunity to clean and/or remove the OMAP PM layer
completely.
With your work, other than the no-op bus throughput API, it's basically
unused. I think that rather than creating a new OMAP PM layer just to
have a a no-op bus throughput function here, I think it's time
to remove OMAP PM completely. This might also give some incentive
for a PM QoS bus throughput constraint as well.
Of course, Paul can make the final decision there whether to remove it
now, but I think it's time.
Just to prove it's usefulness (or lack thereof), Here's a hack that
combined with your patch 1/8 shows that it is pretty easy to remove.
Kevin
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index a5b7a23..e819d59 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -74,6 +74,13 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
{ "dss_hdmi", "omapdss_hdmi", -1 },
};
+static int omap_display_get_context_loss_count(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return omap_device_get_context_loss_count(pdev);
+}
+
int __init omap_display_init(struct omap_dss_board_info *board_data)
{
int r = 0;
@@ -98,7 +105,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
pdata.board_data = board_data;
pdata.board_data->get_context_loss_count =
- omap_pm_get_dev_context_loss_count;
+ omap_display_get_context_loss_count;
for (i = 0; i < oh_count; i++) {
oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index a9b45c7..fc001f7 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -36,7 +36,9 @@ static u16 control_mmc1;
static int hsmmc_get_context_loss(struct device *dev)
{
- return omap_pm_get_dev_context_loss_count(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return omap_device_get_context_loss_count(pdev);
}
#else
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 132724c..6e8794a 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -386,7 +386,7 @@ void __init omap2_init_common_infrastructure(void)
_set_hwmod_postsetup_state,
&postsetup_state);
- omap_pm_if_early_init();
+ /* omap_pm_if_early_init(); */
if (cpu_is_omap2420())
omap2420_clk_init();
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 4411163..ca978c0 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -243,10 +243,10 @@ static int option_set(void *data, u64 val)
*option = val;
if (option == &enable_off_mode) {
- if (val)
- omap_pm_enable_off_mode();
- else
- omap_pm_disable_off_mode();
+ /* if (val) */
+ /* omap_pm_enable_off_mode(); */
+ /* else */
+ /* omap_pm_disable_off_mode(); */
if (cpu_is_omap34xx())
omap3_pm_off_mode_enable(val);
}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 472bf22..59e7533 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -243,7 +243,7 @@ static void __init omap4_init_voltages(void)
static int __init omap2_common_pm_init(void)
{
omap2_init_processor_devices();
- omap_pm_if_init();
+ /* omap_pm_if_init(); */
return 0;
}
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f0233e6..3a2268c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -31,4 +31,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+#obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints
2011-09-15 22:46 ` Kevin Hilman
@ 2011-09-16 15:39 ` Jean Pihet
2011-09-16 16:06 ` Kevin Hilman
0 siblings, 1 reply; 17+ messages in thread
From: Jean Pihet @ 2011-09-16 15:39 UTC (permalink / raw)
To: Kevin Hilman
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Kevin,
On Fri, Sep 16, 2011 at 12:46 AM, Kevin Hilman <khilman@ti.com> wrote:
> Hi Jean,
>
> Jean Pihet <jean.pihet@newoldbits.com> writes:
>
>> Convert the driver from the outdated omap_pm_set_max_mpu_wakeup_lat
>> API to the new PM QoS API.
>> Since the constraint is on the MPU subsystem, use the PM_QOS_CPU_DMA_LATENCY
>> class of PM QoS. The resulting MPU constraints are used by cpuidle to
>> decide the next power state of the MPU subsystem.
>>
>> Currently only OMAP3 is placing constraints on the MPU.
>>
>> Signed-off-by: Jean Pihet <j-pihet@ti.com>
>
> [...]
>
>> @@ -648,8 +648,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
>> if (r < 0)
>> goto out;
>>
>> - if (dev->set_mpu_wkup_lat != NULL)
>> - dev->set_mpu_wkup_lat(dev->dev, dev->latency);
>> + /*
>> + * When waiting for completion of a i2c transfer, we need to
>> + * set a wake up latency constraint for the MPU. This is to
>> + * ensure quick enough wakeup from idle, when transfer
>> + * completes.
>> + * Used on OMAP3 Only
>> + */
>> + if (cpu_is_omap34xx())
>
> We don't want any cpu_is_* checking in drivers.
>
> If this is only done on certain SoCs, then a flag should be passed from
> device init code via pdata.
>
> That being said, I don't see why this shouldn't be set for all SoCs
> since it's using the FIFO size to determine the latency.
I am OK to have the constraints active for all OMAPs. Side question:
what if different SOCs need different values for the constraint?
>
> Kevin
>
Regards,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
2011-09-15 23:47 ` Kevin Hilman
@ 2011-09-16 15:43 ` Jean Pihet
2011-09-16 15:56 ` Kevin Hilman
0 siblings, 1 reply; 17+ messages in thread
From: Jean Pihet @ 2011-09-16 15:43 UTC (permalink / raw)
To: Kevin Hilman
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Kevin,
On Fri, Sep 16, 2011 at 1:47 AM, Kevin Hilman <khilman@ti.com> wrote:
> Jean Pihet <jean.pihet@newoldbits.com> writes:
>
>> 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.
>>
>> Note: the bus throughput function is implemented but currently is
>> a no-op. A new PM QoS class for the bus throughput needs to be
>> added.
>>
>> 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>
>
> This patch does 2 things.
>
> 1) removes the MPU lat stuff from the OMAP PM layer (since it's now
> available in a generic form
> 2) implements device wake-up latency constraints
>
> This should be broken up into two parts.
>
> Also, this patch seems to remove a bunch of stuff that was just added in
> patch 2/8. Probably best to create the new OMAP PM layer after remving
> the unused stuff.
>
> It think the code using the new per-device PM QoS API should also live
> outside the OMAP PM layer, since it's not related, and we want to get
> rid of the OMAP PM layer eventually.
>
> Speaking of which..., the more I think about it, the more I think we
> should take this opportunity to clean and/or remove the OMAP PM layer
> completely.
I agree completely, the OMAP PM 'plugin' layer is useless and anyway
an empty implementation for now.
> With your work, other than the no-op bus throughput API, it's basically
> unused. I think that rather than creating a new OMAP PM layer just to
> have a a no-op bus throughput function here, I think it's time
> to remove OMAP PM completely.
Ok. The only useful code is to register a PM QoS notifier in order to
apply the constraints to the power domains.
Are you suggesting to move this code to e.g. pmxxx.c?
> This might also give some incentive
> for a PM QoS bus throughput constraint as well.
Sure the tput constraints should be implemented as well.
>
> Of course, Paul can make the final decision there whether to remove it
> now, but I think it's time.
>
> Just to prove it's usefulness (or lack thereof), Here's a hack that
> combined with your patch 1/8 shows that it is pretty easy to remove.
>
> Kevin
Thanks!
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
2011-09-16 15:43 ` Jean Pihet
@ 2011-09-16 15:56 ` Kevin Hilman
0 siblings, 0 replies; 17+ messages in thread
From: Kevin Hilman @ 2011-09-16 15:56 UTC (permalink / raw)
To: Jean Pihet
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Jean Pihet <jean.pihet@newoldbits.com> writes:
> Kevin,
>
> On Fri, Sep 16, 2011 at 1:47 AM, Kevin Hilman <khilman@ti.com> wrote:
>> Jean Pihet <jean.pihet@newoldbits.com> writes:
>>
>>> 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.
>>>
>>> Note: the bus throughput function is implemented but currently is
>>> a no-op. A new PM QoS class for the bus throughput needs to be
>>> added.
>>>
>>> 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>
>>
>> This patch does 2 things.
>>
>> 1) removes the MPU lat stuff from the OMAP PM layer (since it's now
>> available in a generic form
>> 2) implements device wake-up latency constraints
>>
>> This should be broken up into two parts.
>>
>> Also, this patch seems to remove a bunch of stuff that was just added in
>> patch 2/8. Probably best to create the new OMAP PM layer after remving
>> the unused stuff.
>>
>> It think the code using the new per-device PM QoS API should also live
>> outside the OMAP PM layer, since it's not related, and we want to get
>> rid of the OMAP PM layer eventually.
>>
>> Speaking of which..., the more I think about it, the more I think we
>> should take this opportunity to clean and/or remove the OMAP PM layer
>> completely.
>
>
> I agree completely, the OMAP PM 'plugin' layer is useless and anyway
> an empty implementation for now.
Great, let's wait for Paul's view on this since he's the maintainer of
the OMAP PM layer.
>> With your work, other than the no-op bus throughput API, it's basically
>> unused. I think that rather than creating a new OMAP PM layer just to
>> have a a no-op bus throughput function here, I think it's time
>> to remove OMAP PM completely.
>
> Ok. The only useful code is to register a PM QoS notifier in order to
> apply the constraints to the power domains.
> Are you suggesting to move this code to e.g. pmxxx.c?
Yes, or simply pm-constraints.c since I guess it should be
SoC-independent.
Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints
2011-09-16 15:39 ` Jean Pihet
@ 2011-09-16 16:06 ` Kevin Hilman
0 siblings, 0 replies; 17+ messages in thread
From: Kevin Hilman @ 2011-09-16 16:06 UTC (permalink / raw)
To: Jean Pihet
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Jean Pihet <jean.pihet@newoldbits.com> writes:
> Kevin,
>
> On Fri, Sep 16, 2011 at 12:46 AM, Kevin Hilman <khilman@ti.com> wrote:
>> Hi Jean,
>>
>> Jean Pihet <jean.pihet@newoldbits.com> writes:
>>
>>> Convert the driver from the outdated omap_pm_set_max_mpu_wakeup_lat
>>> API to the new PM QoS API.
>>> Since the constraint is on the MPU subsystem, use the PM_QOS_CPU_DMA_LATENCY
>>> class of PM QoS. The resulting MPU constraints are used by cpuidle to
>>> decide the next power state of the MPU subsystem.
>>>
>>> Currently only OMAP3 is placing constraints on the MPU.
>>>
>>> Signed-off-by: Jean Pihet <j-pihet@ti.com>
>>
>> [...]
>>
>>> @@ -648,8 +648,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
>>> if (r < 0)
>>> goto out;
>>>
>>> - if (dev->set_mpu_wkup_lat != NULL)
>>> - dev->set_mpu_wkup_lat(dev->dev, dev->latency);
>>> + /*
>>> + * When waiting for completion of a i2c transfer, we need to
>>> + * set a wake up latency constraint for the MPU. This is to
>>> + * ensure quick enough wakeup from idle, when transfer
>>> + * completes.
>>> + * Used on OMAP3 Only
>>> + */
>>> + if (cpu_is_omap34xx())
>>
>> We don't want any cpu_is_* checking in drivers.
>>
>> If this is only done on certain SoCs, then a flag should be passed from
>> device init code via pdata.
>>
>> That being said, I don't see why this shouldn't be set for all SoCs
>> since it's using the FIFO size to determine the latency.
> I am OK to have the constraints active for all OMAPs. Side question:
> what if different SOCs need different values for the constraint?
This latency calculation is based on FIFO size and drain rate, so it
should be completely SoC independent.
However, if for some reason there are SoC dependencies, the SoC specific
parts need to be passed in to the driver.
Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/8] OMAP2+: powerdomain: control power domains next state
2011-09-02 13:13 ` [PATCH 3/8] OMAP2+: powerdomain: control power domains next state Jean Pihet
@ 2011-09-16 18:27 ` Kevin Hilman
0 siblings, 0 replies; 17+ messages in thread
From: Kevin Hilman @ 2011-09-16 18:27 UTC (permalink / raw)
To: Jean Pihet
Cc: Linux PM mailing list, linux-omap, Rafael J. Wysocki,
Paul Walmsley, magnus.damm, Todd Poynor, Jean Pihet
Jean Pihet <jean.pihet@newoldbits.com> writes:
> 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>
[...]
> @@ -191,6 +198,77 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
> 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 upon success.
> + */
> +static int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm,
> + long min_latency)
> +{
> + int ret = 0, new_state = 0;
> +
> + if (!pwrdm) {
> + WARN(1, "powerdomain: %s: invalid parameter(s)", __func__);
> + return -EINVAL;
> + }
> +
> + /*
> + * Apply constraints to power domains by programming
> + * the pwrdm next power state.
> + */
> +
> + /* Find 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 ||
> + pwrdm->wakeup_lat[new_state] <= min_latency)
Since min_latency is signed, this is a signed compare. In later patches
you've defined the UNSUP_STATE to be -1, which will always be <=
min_latency whn using a signed compare.
So, won't this always end up picking the first state marked as
UNSUP_STATE?
> + break;
> + }
Kevin
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2011-09-16 18:27 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-02 13:13 [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
2011-09-02 13:13 ` [PATCH 1/8] OMAP: convert I2C driver to PM QoS for latency constraints Jean Pihet
2011-09-15 22:46 ` Kevin Hilman
2011-09-16 15:39 ` Jean Pihet
2011-09-16 16:06 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 2/8] OMAP: PM: create a PM layer plugin for per-device constraints Jean Pihet
2011-09-02 13:13 ` [PATCH 3/8] OMAP2+: powerdomain: control power domains next state Jean Pihet
2011-09-16 18:27 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 4/8] OMAP3: powerdomain data: add wake-up latency figures Jean Pihet
2011-09-02 13:13 ` [PATCH 5/8] OMAP2+: omap_hwmod: manage the wake-up latency constraints Jean Pihet
2011-09-02 13:13 ` [PATCH 6/8] OMAP: PM CONSTRAINTS: implement the devices " Jean Pihet
2011-09-15 23:47 ` Kevin Hilman
2011-09-16 15:43 ` Jean Pihet
2011-09-16 15:56 ` Kevin Hilman
2011-09-02 13:13 ` [PATCH 7/8] OMAP2+: cpuidle only influences the MPU state Jean Pihet
2011-09-02 13:13 ` [PATCH 8/8] OMAP3: update cpuidle latency and threshold figures Jean Pihet
2011-09-15 8:57 ` [PATCH 0/8] PM QoS: implement the OMAP low level constraints management code Jean Pihet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox