All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
@ 2011-06-24 14:37 jean.pihet
  2011-06-24 14:37 ` [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist jean.pihet
                   ` (21 more replies)
  0 siblings, 22 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

This patch set is in an RFC state, for review and comments.

In order to implement the new class in PM QoS the following changes have been made:

1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_WAKEUP_LATENCY).
Due to the per-device nature of the new class the constraints lists are stored inside the device dev_pm_info struct instead of the internal per-class constraints lists.
The new class is only available from kernel drivers and so is not exported to user space.

2. Make the pm_qos_add_request API more generic by using a struct pm_qos_parameters parameter. This allows easy extension in the future.

3. Upon a change of the strongest constraint in the PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used to take action on the system. This is the proposed way to have PM QoS and the platform dependant code to interact with each other, cf. 4 below.
The notification mechanism now passes the constraint request struct ptr in order for the notifier callback to have access to the full set of constraint data, e.g. the struct device ptr.

4. cpuidle interaction with the OMAP3 cpuidle handler
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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via the device 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.

5. Update the pm_qos_add_request callers to the generic API

6. Minor clean-ups and rename of struct fields

Questions:
1. How to retrieve the device ptr from a given device driver in order to add a constraint on it?
2. The device struct has been extended with the power domain information. Can this be used to apply the constraints on power domains, as proposed by [1]?

On-going developments, patches in preparation:
1. write Documentation for the new PM QoS class
2. validate the constraints framework on OMAP3&4
3. refine the power domains wake-up latency and the cpuidle figures

[1] http://marc.info/?l=linux-omap&m=130451613408148&w=2

Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.


Jean Pihet (8):
  PM: add a per-device wake-up latency constraints plist
  PM: extend PM QoS with per-device wake-up 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

Vishwanath BS (1):
  OMAP4: powerdomain data: add wake-up latency figures

 arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
 arch/arm/mach-omap2/pm.h                     |   17 ++-
 arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
 arch/arm/mach-omap2/powerdomain.h            |   33 +++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
 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     |  344 ++++++++++++++++++++++++++
 arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
 drivers/base/power/main.c                    |    1 +
 drivers/i2c/busses/i2c-omap.c                |   35 ++-
 drivers/media/video/via-camera.c             |    5 +-
 drivers/net/e1000e/netdev.c                  |    9 +-
 drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
 include/linux/pm.h                           |    2 +
 include/linux/pm_qos_params.h                |   40 ++--
 kernel/pm_qos_params.c                       |  142 ++++++-----
 sound/core/pcm_native.c                      |    8 +-
 23 files changed, 939 insertions(+), 367 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

-- 
1.7.4.1


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
@ 2011-06-24 14:37 ` jean.pihet
  2011-06-24 14:37 ` jean.pihet
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Add the field wakeup_lat_plist_head in the struct dev_pm_info
and the initialization of the plist in device_pm_init.

This enables the implementation of per-device constraints in
PM QoS.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 drivers/base/power/main.c |    1 +
 include/linux/pm.h        |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index aa632020..6a096d1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -64,6 +64,7 @@ void device_pm_init(struct device *dev)
 	spin_lock_init(&dev->power.lock);
 	pm_runtime_init(dev);
 	INIT_LIST_HEAD(&dev->power.entry);
+	plist_head_init(&dev->power.wakeup_lat_plist_head, &dev->power.lock);
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 3160648..35fe682 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -22,6 +22,7 @@
 #define _LINUX_PM_H
 
 #include <linux/list.h>
+#include <linux/plist.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
@@ -462,6 +463,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
+	struct plist_head	wakeup_lat_plist_head;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
  2011-06-24 14:37 ` [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist jean.pihet
@ 2011-06-24 14:37 ` jean.pihet
  2011-06-24 14:37 ` [RFC/PATCH 2/9] PM: extend PM QoS with per-device wake-up constraints jean.pihet
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Add the field wakeup_lat_plist_head in the struct dev_pm_info
and the initialization of the plist in device_pm_init.

This enables the implementation of per-device constraints in
PM QoS.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 drivers/base/power/main.c |    1 +
 include/linux/pm.h        |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index aa632020..6a096d1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -64,6 +64,7 @@ void device_pm_init(struct device *dev)
 	spin_lock_init(&dev->power.lock);
 	pm_runtime_init(dev);
 	INIT_LIST_HEAD(&dev->power.entry);
+	plist_head_init(&dev->power.wakeup_lat_plist_head, &dev->power.lock);
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 3160648..35fe682 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -22,6 +22,7 @@
 #define _LINUX_PM_H
 
 #include <linux/list.h>
+#include <linux/plist.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
@@ -462,6 +463,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
+	struct plist_head	wakeup_lat_plist_head;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 2/9] PM: extend PM QoS with per-device wake-up constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (2 preceding siblings ...)
  2011-06-24 14:37 ` [RFC/PATCH 2/9] PM: extend PM QoS with per-device wake-up constraints jean.pihet
@ 2011-06-24 14:37 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 3/9] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

- add a new PM QoS class PM_QOS_DEV_WAKEUP_LATENCY for device wake-up
constraints. Due to the per-device nature of the new class the constraints
list is stored inside the device dev_pm_info struct instead of the internal
per-class constraints lists.
The new class is only available from kernel drivers and so is not exported
to user space.
The new class is used to put constraints on given devices in the system
while the existing PM_QOS_CPU_DMA_LATENCY class is used by cpuidle to
determine the next MPU subsystem state.

- make the pm_qos_add_request API more generic by using a struct
pm_qos_parameters parameter

- the notification mechanism now passes the constraint request struct ptr
in order for the notifier callback to have access to the full set of
constraint data, e.g. the struct device ptr

- update the pm_qos_add_request callers to the generic API

- minor clean-ups and rename of struct fields

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/i2c.c               |   20 -----
 drivers/i2c/busses/i2c-omap.c          |   35 +++++---
 drivers/media/video/via-camera.c       |    5 +-
 drivers/net/e1000e/netdev.c            |    9 ++-
 drivers/net/wireless/ipw2x00/ipw2100.c |    6 +-
 include/linux/pm_qos_params.h          |   40 ++++++----
 kernel/pm_qos_params.c                 |  142 ++++++++++++++++++-------------
 sound/core/pcm_native.c                |    8 ++-
 8 files changed, 149 insertions(+), 116 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 58a58c7..7b53a91 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_params.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_list pm_qos_request;
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
@@ -641,6 +641,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
 	int i;
 	int r;
+	struct pm_qos_parameters pm_qos_params;
 
 	omap_i2c_unidle(dev);
 
@@ -648,8 +649,19 @@ 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.
+	 * Only OMAP3 has support for constraints
+	 */
+	if (cpu_is_omap34xx()) {
+		pm_qos_params.dev = dev->dev;
+		pm_qos_params.class = PM_QOS_DEV_WAKEUP_LATENCY;
+		pm_qos_params.value = dev->latency;
+		pm_qos_add_request(&dev->pm_qos_request, &pm_qos_params);
+	}
 
 	for (i = 0; i < num; i++) {
 		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -657,8 +669,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 +1019,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 +1075,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 device wakeup latency constraint */
+		if (cpu_is_omap34xx())
 			dev->latency = (1000000 * dev->fifo_size) /
 				       (1000 * speed / 8);
 	}
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048..5ca12e2 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -1086,6 +1086,7 @@ static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
 {
 	struct via_camera *cam = priv;
 	int ret = 0;
+	struct pm_qos_parameters pm_qos_params;
 
 	if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1120,7 +1121,9 @@ static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
 	 * requirement which will keep the CPU out of the deeper sleep
 	 * states.
 	 */
-	pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+	pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+	pm_qos_params.value = 50;
+	pm_qos_add_request(&cam->qos_request, &pm_qos_params);
 	/*
 	 * Fire things up.
 	 */
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 3310c3d..c4cce8a 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3604,6 +3604,7 @@ static int e1000_open(struct net_device *netdev)
 	struct e1000_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
 	int err;
+	struct pm_qos_parameters pm_qos_params;
 
 	/* disallow open during test */
 	if (test_bit(__E1000_TESTING, &adapter->state))
@@ -3641,10 +3642,12 @@ static int e1000_open(struct net_device *netdev)
 
 	/* DMA latency requirement to workaround early-receive/jumbo issue */
 	if ((adapter->flags & FLAG_HAS_ERT) ||
-	    (adapter->hw.mac.type == e1000_pch2lan))
+	    (adapter->hw.mac.type == e1000_pch2lan)) {
+		pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+		pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
 		pm_qos_add_request(&adapter->netdev->pm_qos_req,
-				   PM_QOS_CPU_DMA_LATENCY,
-				   PM_QOS_DEFAULT_VALUE);
+				   &pm_qos_params);
+	}
 
 	/*
 	 * before we allocate an interrupt, we must be ready to handle it.
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 4430775..585ad04 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -6643,12 +6643,14 @@ static struct pci_driver ipw2100_pci_driver = {
 static int __init ipw2100_init(void)
 {
 	int ret;
+	struct pm_qos_parameters pm_qos_params;
 
 	printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 	printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
-	pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-			   PM_QOS_DEFAULT_VALUE);
+	pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+	pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
+	pm_qos_add_request(&ipw2100_pm_qos_req, &pm_qos_params);
 
 	ret = pci_register_driver(&ipw2100_pci_driver);
 	if (ret)
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index a7d87f9..e6e16cb 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -8,31 +8,41 @@
 #include <linux/notifier.h>
 #include <linux/miscdevice.h>
 
-#define PM_QOS_RESERVED 0
-#define PM_QOS_CPU_DMA_LATENCY 1
-#define PM_QOS_NETWORK_LATENCY 2
-#define PM_QOS_NETWORK_THROUGHPUT 3
+#define	PM_QOS_RESERVED			0
+#define	PM_QOS_CPU_DMA_LATENCY		1
+#define	PM_QOS_DEV_WAKEUP_LATENCY	2
+#define	PM_QOS_NETWORK_LATENCY		3
+#define	PM_QOS_NETWORK_THROUGHPUT	4
 
-#define PM_QOS_NUM_CLASSES 4
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_NUM_CLASSES		5
+#define PM_QOS_DEFAULT_VALUE		-1
 
-#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
+#define	PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
+#define	PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE	0
+#define	PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
+#define	PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 
 struct pm_qos_request_list {
 	struct plist_node list;
-	int pm_qos_class;
+	int class;
+	struct device *dev;
 };
 
-void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
+struct pm_qos_parameters {
+	int class;
+	struct device *dev;
+	s32 value;
+};
+
+void pm_qos_add_request(struct pm_qos_request_list *l,
+			struct pm_qos_parameters *params);
 void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		s32 new_value);
+			   s32 new_value);
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
 
-int pm_qos_request(int pm_qos_class);
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_request(int class);
+int pm_qos_add_notifier(int class, struct notifier_block *notifier);
+int pm_qos_remove_notifier(int class, struct notifier_block *notifier);
 int pm_qos_request_active(struct pm_qos_request_list *req);
 
 #endif
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index 6824ca7..3d43d63 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -82,6 +82,15 @@ static struct pm_qos_object cpu_dma_pm_qos = {
 	.type = PM_QOS_MIN,
 };
 
+static BLOCKING_NOTIFIER_HEAD(dev_wakeup_lat_notifier);
+static struct pm_qos_object dev_wakeup_lat_pm_qos = {
+	.notifiers = &dev_wakeup_lat_notifier,
+	.name = "dev_wakeup_latency",
+	.target_value = PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN,
+};
+
 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
 static struct pm_qos_object network_lat_pm_qos = {
 	.requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
@@ -107,6 +116,7 @@ static struct pm_qos_object network_throughput_pm_qos = {
 static struct pm_qos_object *pm_qos_array[] = {
 	&null_pm_qos,
 	&cpu_dma_pm_qos,
+	&dev_wakeup_lat_pm_qos,
 	&network_lat_pm_qos,
 	&network_throughput_pm_qos
 };
@@ -155,11 +165,12 @@ static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
 	o->target_value = value;
 }
 
-static void update_target(struct pm_qos_object *o, struct plist_node *node,
-			  int del, int value)
+static void update_target(struct pm_qos_request_list *req, int del, int value)
 {
 	unsigned long flags;
 	int prev_value, curr_value;
+	struct pm_qos_object *o = pm_qos_array[req->class];
+	struct plist_node *node = &req->list;
 
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	prev_value = pm_qos_get_value(o);
@@ -179,13 +190,14 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node,
 		plist_add(node, &o->requests);
 	}
 	curr_value = pm_qos_get_value(o);
-	pm_qos_set_value(o, curr_value);
+	if (req->class != PM_QOS_DEV_WAKEUP_LATENCY)
+		pm_qos_set_value(o, curr_value);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 
 	if (prev_value != curr_value)
 		blocking_notifier_call_chain(o->notifiers,
 					     (unsigned long)curr_value,
-					     NULL);
+					     req);
 }
 
 static int register_pm_qos_misc(struct pm_qos_object *qos)
@@ -199,65 +211,72 @@ static int register_pm_qos_misc(struct pm_qos_object *qos)
 
 static int find_pm_qos_object_by_minor(int minor)
 {
-	int pm_qos_class;
+	int class;
 
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+	for (class = 0;
+		class < PM_QOS_NUM_CLASSES; class++) {
 		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
+			pm_qos_array[class]->pm_qos_power_miscdev.minor)
+			return class;
 	}
 	return -1;
 }
 
 /**
  * pm_qos_request - returns current system wide qos expectation
- * @pm_qos_class: identification of which qos value is requested
+ * @class: identification of which qos value is requested
  *
  * This function returns the current target value.
  */
-int pm_qos_request(int pm_qos_class)
+int pm_qos_request(int class)
 {
-	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
+	if (class == PM_QOS_DEV_WAKEUP_LATENCY)
+		return pm_qos_get_value(pm_qos_array[class]);
+	else
+		return pm_qos_read_value(pm_qos_array[class]);
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
 int pm_qos_request_active(struct pm_qos_request_list *req)
 {
-	return req->pm_qos_class != 0;
+	return req->class != 0;
 }
 EXPORT_SYMBOL_GPL(pm_qos_request_active);
 
 /**
  * pm_qos_add_request - inserts new qos request into the list
  * @dep: pointer to a preallocated handle
- * @pm_qos_class: identifies which list of qos request to use
- * @value: defines the qos request
+ * @params: request parameters
  *
- * This function inserts a new entry in the pm_qos_class list of requested qos
+ * This function inserts a new entry in the class list of requested qos
  * performance characteristics.  It recomputes the aggregate QoS expectations
- * for the pm_qos_class of parameters and initializes the pm_qos_request_list
- * handle.  Caller needs to save this handle for later use in updates and
+ * for the class of parameters and initializes the pm_qos_request_list
+ * handle. Caller needs to save this handle for later use in updates and
  * removal.
  */
 
-void pm_qos_add_request(struct pm_qos_request_list *dep,
-			int pm_qos_class, s32 value)
+void pm_qos_add_request(struct pm_qos_request_list *pm_qos_req,
+			struct pm_qos_parameters *pm_qos_params)
 {
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	struct pm_qos_object *o =  pm_qos_array[pm_qos_params->class];
 	int new_value;
 
-	if (pm_qos_request_active(dep)) {
-		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+	if (pm_qos_params->class == PM_QOS_DEV_WAKEUP_LATENCY) {
+		o->requests = pm_qos_req->dev->power.wakeup_lat_plist_head;
+	} else if (pm_qos_request_active(pm_qos_req)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
+		     "added request\n");
 		return;
 	}
-	if (value == PM_QOS_DEFAULT_VALUE)
+
+	if (pm_qos_params->value == PM_QOS_DEFAULT_VALUE)
 		new_value = o->default_value;
 	else
-		new_value = value;
-	plist_node_init(&dep->list, new_value);
-	dep->pm_qos_class = pm_qos_class;
-	update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
+		new_value = pm_qos_params->value;
+	plist_node_init(&pm_qos_req->list, new_value);
+	pm_qos_req->class = pm_qos_params->class;
+	pm_qos_req->dev = pm_qos_params->dev;
+	update_target(pm_qos_req, 0, PM_QOS_DEFAULT_VALUE);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
@@ -266,8 +285,8 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
  * @pm_qos_req : handle to list element holding a pm_qos request to use
  * @value: defines the qos request
  *
- * Updates an existing qos request for the pm_qos_class of parameters along
- * with updating the target pm_qos_class value.
+ * Updates an existing qos request for the class of parameters along
+ * with updating the target class value.
  *
  * Attempts are made to make this code callable on hot code paths.
  */
@@ -275,25 +294,25 @@ void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
 			   s32 new_value)
 {
 	s32 temp;
-	struct pm_qos_object *o;
+	struct pm_qos_object *o = pm_qos_array[pm_qos_req->class];
 
 	if (!pm_qos_req) /*guard against callers passing in null */
 		return;
 
-	if (!pm_qos_request_active(pm_qos_req)) {
-		WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
+	if ((pm_qos_req->class != PM_QOS_DEV_WAKEUP_LATENCY) &&
+	    (!pm_qos_request_active(pm_qos_req))) {
+		WARN(1, KERN_ERR "pm_qos_update_request() called for unknown "
+		     "object\n");
 		return;
 	}
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-
 	if (new_value == PM_QOS_DEFAULT_VALUE)
 		temp = o->default_value;
 	else
 		temp = new_value;
 
 	if (temp != pm_qos_req->list.prio)
-		update_target(o, &pm_qos_req->list, 0, temp);
+		update_target(pm_qos_req, 0, temp);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
@@ -302,42 +321,41 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
  * @pm_qos_req: handle to request list element
  *
  * Will remove pm qos request from the list of requests and
- * recompute the current target value for the pm_qos_class.  Call this
+ * recompute the current target value for the class.  Call this
  * on slow code paths.
  */
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
 {
-	struct pm_qos_object *o;
-
 	if (pm_qos_req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
 
-	if (!pm_qos_request_active(pm_qos_req)) {
-		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+	if ((pm_qos_req->class != PM_QOS_DEV_WAKEUP_LATENCY) &&
+	    (!pm_qos_request_active(pm_qos_req))) {
+		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown "
+		     "object\n");
 		return;
 	}
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
+	update_target(pm_qos_req, 1, PM_QOS_DEFAULT_VALUE);
 	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_request);
 
 /**
  * pm_qos_add_notifier - sets notification entry for changes to target value
- * @pm_qos_class: identifies which qos target changes should be notified.
+ * @class: identifies which qos target changes should be notified.
  * @notifier: notifier block managed by caller.
  *
  * will register the notifier into a notification chain that gets called
- * upon changes to the pm_qos_class target value.
+ * upon changes to the class target value.
  */
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+int pm_qos_add_notifier(int class, struct notifier_block *notifier)
 {
 	int retval;
 
 	retval = blocking_notifier_chain_register(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
+			pm_qos_array[class]->notifiers, notifier);
 
 	return retval;
 }
@@ -345,18 +363,18 @@ EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
 
 /**
  * pm_qos_remove_notifier - deletes notification entry from chain.
- * @pm_qos_class: identifies which qos target changes are notified.
+ * @class: identifies which qos target changes are notified.
  * @notifier: notifier block to be removed.
  *
  * will remove the notifier from the notification chain that gets called
- * upon changes to the pm_qos_class target value.
+ * upon changes to the class target value.
  */
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 {
 	int retval;
 
 	retval = blocking_notifier_chain_unregister(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
+			pm_qos_array[class]->notifiers, notifier);
 
 	return retval;
 }
@@ -364,15 +382,17 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
 static int pm_qos_power_open(struct inode *inode, struct file *filp)
 {
-	long pm_qos_class;
+	struct pm_qos_parameters pm_qos_params;
 
-	pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
-	if (pm_qos_class >= 0) {
-               struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
+	pm_qos_params.class = find_pm_qos_object_by_minor(iminor(inode));
+	if (pm_qos_params.class >= 0) {
+		struct pm_qos_request_list *req = kzalloc(sizeof(*req),
+							  GFP_KERNEL);
 		if (!req)
 			return -ENOMEM;
 
-		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+		pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
+		pm_qos_add_request(req, &pm_qos_params);
 		filp->private_data = req;
 
 		if (filp->private_data)
@@ -406,7 +426,7 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	if (!pm_qos_request_active(pm_qos_req))
 		return -EINVAL;
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	o = pm_qos_array[pm_qos_req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	value = pm_qos_get_value(o);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -462,18 +482,20 @@ static int __init pm_qos_power_init(void)
 
 	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
 	if (ret < 0) {
-		printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
+		printk(KERN_ERR
+		       "pm_qos_param: cpu_dma_latency setup failed\n");
 		return ret;
 	}
 	ret = register_pm_qos_misc(&network_lat_pm_qos);
 	if (ret < 0) {
-		printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
+		printk(KERN_ERR
+		       "pm_qos_param: network_latency setup failed\n");
 		return ret;
 	}
 	ret = register_pm_qos_misc(&network_throughput_pm_qos);
 	if (ret < 0)
 		printk(KERN_ERR
-			"pm_qos_param: network_throughput setup failed\n");
+		       "pm_qos_param: network_throughput setup failed\n");
 
 	return ret;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 1c6be91..a19605c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -375,6 +375,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 	int err, usecs;
 	unsigned int bits;
 	snd_pcm_uframes_t frames;
+	struct pm_qos_parameters pm_qos_params;
 
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
@@ -455,9 +456,12 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	if (pm_qos_request_active(&substream->latency_pm_qos_req))
 		pm_qos_remove_request(&substream->latency_pm_qos_req);
-	if ((usecs = period_to_usecs(runtime)) >= 0)
+	if ((usecs = period_to_usecs(runtime)) >= 0) {
+		pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+		pm_qos_params.value = usecs;
 		pm_qos_add_request(&substream->latency_pm_qos_req,
-				   PM_QOS_CPU_DMA_LATENCY, usecs);
+				   &pm_qos_params);
+	}
 	return 0;
  _error:
 	/* hardware might be unusable from this time,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 2/9] PM: extend PM QoS with per-device wake-up constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
  2011-06-24 14:37 ` [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist jean.pihet
  2011-06-24 14:37 ` jean.pihet
@ 2011-06-24 14:37 ` jean.pihet
  2011-06-24 14:37 ` jean.pihet
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

- add a new PM QoS class PM_QOS_DEV_WAKEUP_LATENCY for device wake-up
constraints. Due to the per-device nature of the new class the constraints
list is stored inside the device dev_pm_info struct instead of the internal
per-class constraints lists.
The new class is only available from kernel drivers and so is not exported
to user space.
The new class is used to put constraints on given devices in the system
while the existing PM_QOS_CPU_DMA_LATENCY class is used by cpuidle to
determine the next MPU subsystem state.

- make the pm_qos_add_request API more generic by using a struct
pm_qos_parameters parameter

- the notification mechanism now passes the constraint request struct ptr
in order for the notifier callback to have access to the full set of
constraint data, e.g. the struct device ptr

- update the pm_qos_add_request callers to the generic API

- minor clean-ups and rename of struct fields

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/i2c.c               |   20 -----
 drivers/i2c/busses/i2c-omap.c          |   35 +++++---
 drivers/media/video/via-camera.c       |    5 +-
 drivers/net/e1000e/netdev.c            |    9 ++-
 drivers/net/wireless/ipw2x00/ipw2100.c |    6 +-
 include/linux/pm_qos_params.h          |   40 ++++++----
 kernel/pm_qos_params.c                 |  142 ++++++++++++++++++-------------
 sound/core/pcm_native.c                |    8 ++-
 8 files changed, 149 insertions(+), 116 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 58a58c7..7b53a91 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_params.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_list pm_qos_request;
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
@@ -641,6 +641,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
 	int i;
 	int r;
+	struct pm_qos_parameters pm_qos_params;
 
 	omap_i2c_unidle(dev);
 
@@ -648,8 +649,19 @@ 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.
+	 * Only OMAP3 has support for constraints
+	 */
+	if (cpu_is_omap34xx()) {
+		pm_qos_params.dev = dev->dev;
+		pm_qos_params.class = PM_QOS_DEV_WAKEUP_LATENCY;
+		pm_qos_params.value = dev->latency;
+		pm_qos_add_request(&dev->pm_qos_request, &pm_qos_params);
+	}
 
 	for (i = 0; i < num; i++) {
 		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -657,8 +669,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 +1019,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 +1075,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 device wakeup latency constraint */
+		if (cpu_is_omap34xx())
 			dev->latency = (1000000 * dev->fifo_size) /
 				       (1000 * speed / 8);
 	}
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048..5ca12e2 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -1086,6 +1086,7 @@ static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
 {
 	struct via_camera *cam = priv;
 	int ret = 0;
+	struct pm_qos_parameters pm_qos_params;
 
 	if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1120,7 +1121,9 @@ static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
 	 * requirement which will keep the CPU out of the deeper sleep
 	 * states.
 	 */
-	pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+	pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+	pm_qos_params.value = 50;
+	pm_qos_add_request(&cam->qos_request, &pm_qos_params);
 	/*
 	 * Fire things up.
 	 */
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 3310c3d..c4cce8a 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3604,6 +3604,7 @@ static int e1000_open(struct net_device *netdev)
 	struct e1000_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
 	int err;
+	struct pm_qos_parameters pm_qos_params;
 
 	/* disallow open during test */
 	if (test_bit(__E1000_TESTING, &adapter->state))
@@ -3641,10 +3642,12 @@ static int e1000_open(struct net_device *netdev)
 
 	/* DMA latency requirement to workaround early-receive/jumbo issue */
 	if ((adapter->flags & FLAG_HAS_ERT) ||
-	    (adapter->hw.mac.type == e1000_pch2lan))
+	    (adapter->hw.mac.type == e1000_pch2lan)) {
+		pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+		pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
 		pm_qos_add_request(&adapter->netdev->pm_qos_req,
-				   PM_QOS_CPU_DMA_LATENCY,
-				   PM_QOS_DEFAULT_VALUE);
+				   &pm_qos_params);
+	}
 
 	/*
 	 * before we allocate an interrupt, we must be ready to handle it.
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 4430775..585ad04 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -6643,12 +6643,14 @@ static struct pci_driver ipw2100_pci_driver = {
 static int __init ipw2100_init(void)
 {
 	int ret;
+	struct pm_qos_parameters pm_qos_params;
 
 	printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 	printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
-	pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-			   PM_QOS_DEFAULT_VALUE);
+	pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+	pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
+	pm_qos_add_request(&ipw2100_pm_qos_req, &pm_qos_params);
 
 	ret = pci_register_driver(&ipw2100_pci_driver);
 	if (ret)
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index a7d87f9..e6e16cb 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -8,31 +8,41 @@
 #include <linux/notifier.h>
 #include <linux/miscdevice.h>
 
-#define PM_QOS_RESERVED 0
-#define PM_QOS_CPU_DMA_LATENCY 1
-#define PM_QOS_NETWORK_LATENCY 2
-#define PM_QOS_NETWORK_THROUGHPUT 3
+#define	PM_QOS_RESERVED			0
+#define	PM_QOS_CPU_DMA_LATENCY		1
+#define	PM_QOS_DEV_WAKEUP_LATENCY	2
+#define	PM_QOS_NETWORK_LATENCY		3
+#define	PM_QOS_NETWORK_THROUGHPUT	4
 
-#define PM_QOS_NUM_CLASSES 4
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_NUM_CLASSES		5
+#define PM_QOS_DEFAULT_VALUE		-1
 
-#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
+#define	PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
+#define	PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE	0
+#define	PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
+#define	PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 
 struct pm_qos_request_list {
 	struct plist_node list;
-	int pm_qos_class;
+	int class;
+	struct device *dev;
 };
 
-void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
+struct pm_qos_parameters {
+	int class;
+	struct device *dev;
+	s32 value;
+};
+
+void pm_qos_add_request(struct pm_qos_request_list *l,
+			struct pm_qos_parameters *params);
 void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		s32 new_value);
+			   s32 new_value);
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
 
-int pm_qos_request(int pm_qos_class);
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_request(int class);
+int pm_qos_add_notifier(int class, struct notifier_block *notifier);
+int pm_qos_remove_notifier(int class, struct notifier_block *notifier);
 int pm_qos_request_active(struct pm_qos_request_list *req);
 
 #endif
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index 6824ca7..3d43d63 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -82,6 +82,15 @@ static struct pm_qos_object cpu_dma_pm_qos = {
 	.type = PM_QOS_MIN,
 };
 
+static BLOCKING_NOTIFIER_HEAD(dev_wakeup_lat_notifier);
+static struct pm_qos_object dev_wakeup_lat_pm_qos = {
+	.notifiers = &dev_wakeup_lat_notifier,
+	.name = "dev_wakeup_latency",
+	.target_value = PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_DEV_WAKEUP_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN,
+};
+
 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
 static struct pm_qos_object network_lat_pm_qos = {
 	.requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
@@ -107,6 +116,7 @@ static struct pm_qos_object network_throughput_pm_qos = {
 static struct pm_qos_object *pm_qos_array[] = {
 	&null_pm_qos,
 	&cpu_dma_pm_qos,
+	&dev_wakeup_lat_pm_qos,
 	&network_lat_pm_qos,
 	&network_throughput_pm_qos
 };
@@ -155,11 +165,12 @@ static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
 	o->target_value = value;
 }
 
-static void update_target(struct pm_qos_object *o, struct plist_node *node,
-			  int del, int value)
+static void update_target(struct pm_qos_request_list *req, int del, int value)
 {
 	unsigned long flags;
 	int prev_value, curr_value;
+	struct pm_qos_object *o = pm_qos_array[req->class];
+	struct plist_node *node = &req->list;
 
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	prev_value = pm_qos_get_value(o);
@@ -179,13 +190,14 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node,
 		plist_add(node, &o->requests);
 	}
 	curr_value = pm_qos_get_value(o);
-	pm_qos_set_value(o, curr_value);
+	if (req->class != PM_QOS_DEV_WAKEUP_LATENCY)
+		pm_qos_set_value(o, curr_value);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 
 	if (prev_value != curr_value)
 		blocking_notifier_call_chain(o->notifiers,
 					     (unsigned long)curr_value,
-					     NULL);
+					     req);
 }
 
 static int register_pm_qos_misc(struct pm_qos_object *qos)
@@ -199,65 +211,72 @@ static int register_pm_qos_misc(struct pm_qos_object *qos)
 
 static int find_pm_qos_object_by_minor(int minor)
 {
-	int pm_qos_class;
+	int class;
 
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+	for (class = 0;
+		class < PM_QOS_NUM_CLASSES; class++) {
 		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
+			pm_qos_array[class]->pm_qos_power_miscdev.minor)
+			return class;
 	}
 	return -1;
 }
 
 /**
  * pm_qos_request - returns current system wide qos expectation
- * @pm_qos_class: identification of which qos value is requested
+ * @class: identification of which qos value is requested
  *
  * This function returns the current target value.
  */
-int pm_qos_request(int pm_qos_class)
+int pm_qos_request(int class)
 {
-	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
+	if (class == PM_QOS_DEV_WAKEUP_LATENCY)
+		return pm_qos_get_value(pm_qos_array[class]);
+	else
+		return pm_qos_read_value(pm_qos_array[class]);
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
 int pm_qos_request_active(struct pm_qos_request_list *req)
 {
-	return req->pm_qos_class != 0;
+	return req->class != 0;
 }
 EXPORT_SYMBOL_GPL(pm_qos_request_active);
 
 /**
  * pm_qos_add_request - inserts new qos request into the list
  * @dep: pointer to a preallocated handle
- * @pm_qos_class: identifies which list of qos request to use
- * @value: defines the qos request
+ * @params: request parameters
  *
- * This function inserts a new entry in the pm_qos_class list of requested qos
+ * This function inserts a new entry in the class list of requested qos
  * performance characteristics.  It recomputes the aggregate QoS expectations
- * for the pm_qos_class of parameters and initializes the pm_qos_request_list
- * handle.  Caller needs to save this handle for later use in updates and
+ * for the class of parameters and initializes the pm_qos_request_list
+ * handle. Caller needs to save this handle for later use in updates and
  * removal.
  */
 
-void pm_qos_add_request(struct pm_qos_request_list *dep,
-			int pm_qos_class, s32 value)
+void pm_qos_add_request(struct pm_qos_request_list *pm_qos_req,
+			struct pm_qos_parameters *pm_qos_params)
 {
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	struct pm_qos_object *o =  pm_qos_array[pm_qos_params->class];
 	int new_value;
 
-	if (pm_qos_request_active(dep)) {
-		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+	if (pm_qos_params->class == PM_QOS_DEV_WAKEUP_LATENCY) {
+		o->requests = pm_qos_req->dev->power.wakeup_lat_plist_head;
+	} else if (pm_qos_request_active(pm_qos_req)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
+		     "added request\n");
 		return;
 	}
-	if (value == PM_QOS_DEFAULT_VALUE)
+
+	if (pm_qos_params->value == PM_QOS_DEFAULT_VALUE)
 		new_value = o->default_value;
 	else
-		new_value = value;
-	plist_node_init(&dep->list, new_value);
-	dep->pm_qos_class = pm_qos_class;
-	update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
+		new_value = pm_qos_params->value;
+	plist_node_init(&pm_qos_req->list, new_value);
+	pm_qos_req->class = pm_qos_params->class;
+	pm_qos_req->dev = pm_qos_params->dev;
+	update_target(pm_qos_req, 0, PM_QOS_DEFAULT_VALUE);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
@@ -266,8 +285,8 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
  * @pm_qos_req : handle to list element holding a pm_qos request to use
  * @value: defines the qos request
  *
- * Updates an existing qos request for the pm_qos_class of parameters along
- * with updating the target pm_qos_class value.
+ * Updates an existing qos request for the class of parameters along
+ * with updating the target class value.
  *
  * Attempts are made to make this code callable on hot code paths.
  */
@@ -275,25 +294,25 @@ void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
 			   s32 new_value)
 {
 	s32 temp;
-	struct pm_qos_object *o;
+	struct pm_qos_object *o = pm_qos_array[pm_qos_req->class];
 
 	if (!pm_qos_req) /*guard against callers passing in null */
 		return;
 
-	if (!pm_qos_request_active(pm_qos_req)) {
-		WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
+	if ((pm_qos_req->class != PM_QOS_DEV_WAKEUP_LATENCY) &&
+	    (!pm_qos_request_active(pm_qos_req))) {
+		WARN(1, KERN_ERR "pm_qos_update_request() called for unknown "
+		     "object\n");
 		return;
 	}
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-
 	if (new_value == PM_QOS_DEFAULT_VALUE)
 		temp = o->default_value;
 	else
 		temp = new_value;
 
 	if (temp != pm_qos_req->list.prio)
-		update_target(o, &pm_qos_req->list, 0, temp);
+		update_target(pm_qos_req, 0, temp);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
@@ -302,42 +321,41 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
  * @pm_qos_req: handle to request list element
  *
  * Will remove pm qos request from the list of requests and
- * recompute the current target value for the pm_qos_class.  Call this
+ * recompute the current target value for the class.  Call this
  * on slow code paths.
  */
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
 {
-	struct pm_qos_object *o;
-
 	if (pm_qos_req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
 
-	if (!pm_qos_request_active(pm_qos_req)) {
-		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+	if ((pm_qos_req->class != PM_QOS_DEV_WAKEUP_LATENCY) &&
+	    (!pm_qos_request_active(pm_qos_req))) {
+		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown "
+		     "object\n");
 		return;
 	}
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
+	update_target(pm_qos_req, 1, PM_QOS_DEFAULT_VALUE);
 	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_request);
 
 /**
  * pm_qos_add_notifier - sets notification entry for changes to target value
- * @pm_qos_class: identifies which qos target changes should be notified.
+ * @class: identifies which qos target changes should be notified.
  * @notifier: notifier block managed by caller.
  *
  * will register the notifier into a notification chain that gets called
- * upon changes to the pm_qos_class target value.
+ * upon changes to the class target value.
  */
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+int pm_qos_add_notifier(int class, struct notifier_block *notifier)
 {
 	int retval;
 
 	retval = blocking_notifier_chain_register(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
+			pm_qos_array[class]->notifiers, notifier);
 
 	return retval;
 }
@@ -345,18 +363,18 @@ EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
 
 /**
  * pm_qos_remove_notifier - deletes notification entry from chain.
- * @pm_qos_class: identifies which qos target changes are notified.
+ * @class: identifies which qos target changes are notified.
  * @notifier: notifier block to be removed.
  *
  * will remove the notifier from the notification chain that gets called
- * upon changes to the pm_qos_class target value.
+ * upon changes to the class target value.
  */
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 {
 	int retval;
 
 	retval = blocking_notifier_chain_unregister(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
+			pm_qos_array[class]->notifiers, notifier);
 
 	return retval;
 }
@@ -364,15 +382,17 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
 static int pm_qos_power_open(struct inode *inode, struct file *filp)
 {
-	long pm_qos_class;
+	struct pm_qos_parameters pm_qos_params;
 
-	pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
-	if (pm_qos_class >= 0) {
-               struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
+	pm_qos_params.class = find_pm_qos_object_by_minor(iminor(inode));
+	if (pm_qos_params.class >= 0) {
+		struct pm_qos_request_list *req = kzalloc(sizeof(*req),
+							  GFP_KERNEL);
 		if (!req)
 			return -ENOMEM;
 
-		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+		pm_qos_params.value = PM_QOS_DEFAULT_VALUE;
+		pm_qos_add_request(req, &pm_qos_params);
 		filp->private_data = req;
 
 		if (filp->private_data)
@@ -406,7 +426,7 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	if (!pm_qos_request_active(pm_qos_req))
 		return -EINVAL;
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	o = pm_qos_array[pm_qos_req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	value = pm_qos_get_value(o);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -462,18 +482,20 @@ static int __init pm_qos_power_init(void)
 
 	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
 	if (ret < 0) {
-		printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
+		printk(KERN_ERR
+		       "pm_qos_param: cpu_dma_latency setup failed\n");
 		return ret;
 	}
 	ret = register_pm_qos_misc(&network_lat_pm_qos);
 	if (ret < 0) {
-		printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
+		printk(KERN_ERR
+		       "pm_qos_param: network_latency setup failed\n");
 		return ret;
 	}
 	ret = register_pm_qos_misc(&network_throughput_pm_qos);
 	if (ret < 0)
 		printk(KERN_ERR
-			"pm_qos_param: network_throughput setup failed\n");
+		       "pm_qos_param: network_throughput setup failed\n");
 
 	return ret;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 1c6be91..a19605c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -375,6 +375,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 	int err, usecs;
 	unsigned int bits;
 	snd_pcm_uframes_t frames;
+	struct pm_qos_parameters pm_qos_params;
 
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
@@ -455,9 +456,12 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	if (pm_qos_request_active(&substream->latency_pm_qos_req))
 		pm_qos_remove_request(&substream->latency_pm_qos_req);
-	if ((usecs = period_to_usecs(runtime)) >= 0)
+	if ((usecs = period_to_usecs(runtime)) >= 0) {
+		pm_qos_params.class = PM_QOS_CPU_DMA_LATENCY;
+		pm_qos_params.value = usecs;
 		pm_qos_add_request(&substream->latency_pm_qos_req,
-				   PM_QOS_CPU_DMA_LATENCY, usecs);
+				   &pm_qos_params);
+	}
 	return 0;
  _error:
 	/* hardware might be unusable from this time,
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 3/9] OMAP PM: create a PM layer plugin for per-device constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (4 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 3/9] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 4/9] OMAP2+: powerdomain: control power domains next state jean.pihet
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 49a4c75..725d942 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -217,6 +217,13 @@ config OMAP_PM_NONE
 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] 37+ messages in thread

* [RFC/PATCH 3/9] OMAP PM: create a PM layer plugin for per-device constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (3 preceding siblings ...)
  2011-06-24 14:37 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 49a4c75..725d942 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -217,6 +217,13 @@ config OMAP_PM_NONE
 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] 37+ messages in thread

* [RFC/PATCH 4/9] OMAP2+: powerdomain: control power domains next state
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (6 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 4/9] OMAP2+: powerdomain: control power domains next state jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 5/9] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

When a wake-up latency constraint is requested or removed the PM QoS
layer notifies the underlying layer with the updated strongest 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 |  187 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++++++-
 2 files changed, 218 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..45697bf 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_params.h>
 #include <trace/events/power.h>
 
 #include "cm2xxx_3xxx.h"
@@ -104,6 +106,12 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	for (i = 0; i < pwrdm->banks; i++)
 		pwrdm->ret_mem_off_counter[i] = 0;
 
+	/* Initialize the per-od wake-up constraints list and spinlock */
+	spin_lock_init(&pwrdm->wkup_lat_plist_lock);
+	plist_head_init(&pwrdm->wkup_lat_plist_head,
+			&pwrdm->wkup_lat_plist_lock);
+
+	/* Initialize the pwrdm state */
 	pwrdm_wait_transition(pwrdm);
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
@@ -191,6 +199,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 0 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 == 0 ||
+		    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 +1009,114 @@ 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_WAKEUP_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;
+	int ret = 0, free_new_user = 0, free_node = 0;
+	long value = 0;
+	unsigned long flags;
+
+	pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
+		 __func__, pwrdm->name, cookie, min_latency);
+
+	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;
+	}
+
+	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;
+			free_new_user = 1;
+			break;
+		}
+	}
+
+	if (min_latency != PM_QOS_DEV_WAKEUP_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;
+		} 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 {
+		/* Remove the constraint from the list */
+		if (!user) {
+			pr_err("%s: Error: no prior constraint to release\n",
+			       __func__);
+			ret = -EINVAL;
+			goto exit_error;
+		}
+
+		plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+		free_node = 1;
+	}
+
+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] 37+ messages in thread

* [RFC/PATCH 4/9] OMAP2+: powerdomain: control power domains next state
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (5 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

When a wake-up latency constraint is requested or removed the PM QoS
layer notifies the underlying layer with the updated strongest 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 |  187 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++++++-
 2 files changed, 218 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..45697bf 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_params.h>
 #include <trace/events/power.h>
 
 #include "cm2xxx_3xxx.h"
@@ -104,6 +106,12 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	for (i = 0; i < pwrdm->banks; i++)
 		pwrdm->ret_mem_off_counter[i] = 0;
 
+	/* Initialize the per-od wake-up constraints list and spinlock */
+	spin_lock_init(&pwrdm->wkup_lat_plist_lock);
+	plist_head_init(&pwrdm->wkup_lat_plist_head,
+			&pwrdm->wkup_lat_plist_lock);
+
+	/* Initialize the pwrdm state */
 	pwrdm_wait_transition(pwrdm);
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
@@ -191,6 +199,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 0 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 == 0 ||
+		    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 +1009,114 @@ 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_WAKEUP_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;
+	int ret = 0, free_new_user = 0, free_node = 0;
+	long value = 0;
+	unsigned long flags;
+
+	pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
+		 __func__, pwrdm->name, cookie, min_latency);
+
+	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;
+	}
+
+	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;
+			free_new_user = 1;
+			break;
+		}
+	}
+
+	if (min_latency != PM_QOS_DEV_WAKEUP_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;
+		} 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 {
+		/* Remove the constraint from the list */
+		if (!user) {
+			pr_err("%s: Error: no prior constraint to release\n",
+			       __func__);
+			ret = -EINVAL;
+			goto exit_error;
+		}
+
+		plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+		free_node = 1;
+	}
+
+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] 37+ messages in thread

* [RFC/PATCH 5/9] OMAP3: powerdomain data: add wake-up latency figures
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (7 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Figures are added to the power domains structs.

Note: the figures are preliminary figures. More accurate measurements
are needed. Also the conditions of measurements shall be investigated
and described.

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 |   77 +++++++++++++++++++++++++++
 1 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 469a920..64446e7 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -31,6 +31,13 @@
 
 /*
  * Powerdomains
+ *
+ * The wakeup_lat values are derived from measurements on
+ * the actual target.
+ *
+ * Note: the latency figures are preliminary and only used
+ * for the constraints framework validation.
+ * Actual figures and measurements conditions shall be added.
  */
 
 static struct powerdomain iva2_pwrdm = {
@@ -52,6 +59,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 +82,13 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_OFF_ON,
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 95,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 45,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -98,6 +119,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] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,6 +149,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] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain dss_pwrdm = {
@@ -136,6 +171,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 +199,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 +221,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 +243,13 @@ static struct powerdomain per_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 200,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 110,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain emu_pwrdm = {
@@ -201,6 +264,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] = 200,
+		[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 usbhost_pwrdm = {
@@ -223,6 +293,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] 37+ messages in thread

* [RFC/PATCH 5/9] OMAP3: powerdomain data: add wake-up latency figures
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (8 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 5/9] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 6/9] OMAP4: " jean.pihet
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Figures are added to the power domains structs.

Note: the figures are preliminary figures. More accurate measurements
are needed. Also the conditions of measurements shall be investigated
and described.

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 |   77 +++++++++++++++++++++++++++
 1 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 469a920..64446e7 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -31,6 +31,13 @@
 
 /*
  * Powerdomains
+ *
+ * The wakeup_lat values are derived from measurements on
+ * the actual target.
+ *
+ * Note: the latency figures are preliminary and only used
+ * for the constraints framework validation.
+ * Actual figures and measurements conditions shall be added.
  */
 
 static struct powerdomain iva2_pwrdm = {
@@ -52,6 +59,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 +82,13 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_OFF_ON,
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 95,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 45,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -98,6 +119,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] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,6 +149,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] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain dss_pwrdm = {
@@ -136,6 +171,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 +199,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 +221,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 +243,13 @@ static struct powerdomain per_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 200,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 110,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain emu_pwrdm = {
@@ -201,6 +264,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] = 200,
+		[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 usbhost_pwrdm = {
@@ -223,6 +293,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] 37+ messages in thread

* [RFC/PATCH 6/9] OMAP4: powerdomain data: add wake-up latency figures
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (9 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Vishwanath BS <vishwanath.bs@ti.com>

This patch adds wake up latency numbers for OMAP4. Note that these are
preliminary numbers and need to be relooked.

Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>

The INACTIVE state is added as unsupported.

Tested on 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/powerdomains44xx_data.c |   85 +++++++++++++++++++++++++++
 1 files changed, 85 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index c4222c7..9b90d88 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -54,6 +54,13 @@ static struct powerdomain core_44xx_pwrdm = {
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -71,6 +78,13 @@ static struct powerdomain gfx_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* gfx_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.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,
+	},
 };
 
 /* abe_44xx_pwrdm: Audio back end power domain */
@@ -91,6 +105,13 @@ static struct powerdomain abe_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* periphmem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* dss_44xx_pwrdm: Display subsystem power domain */
@@ -109,6 +130,13 @@ static struct powerdomain dss_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* dss_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* tesla_44xx_pwrdm: Tesla processor power domain */
@@ -131,6 +159,13 @@ static struct powerdomain tesla_44xx_pwrdm = {
 		[2] = PWRSTS_ON,	/* tesla_l2 */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* wkup_44xx_pwrdm: Wake-up power domain */
@@ -164,6 +199,13 @@ static struct powerdomain cpu0_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu0_l1 */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -181,6 +223,13 @@ static struct powerdomain cpu1_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu1_l1 */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* emu_44xx_pwrdm: Emulation power domain */
@@ -218,6 +267,13 @@ static struct powerdomain mpu_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* mpu_l2 */
 		[2] = PWRSTS_ON,	/* mpu_ram */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* ivahd_44xx_pwrdm: IVA-HD power domain */
@@ -242,6 +298,13 @@ static struct powerdomain ivahd_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* tcm2_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* cam_44xx_pwrdm: Camera subsystem power domain */
@@ -259,6 +322,13 @@ static struct powerdomain cam_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* cam_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.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,
+	},
 };
 
 /* l3init_44xx_pwrdm: L3 initators pheripherals power domain  */
@@ -277,6 +347,13 @@ static struct powerdomain l3init_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* l3init_bank1 */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* l4per_44xx_pwrdm: Target peripherals power domain */
@@ -297,6 +374,13 @@ static struct powerdomain l4per_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* retained_bank */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -353,3 +437,4 @@ void __init omap44xx_powerdomains_init(void)
 {
 	pwrdm_init(powerdomains_omap44xx, &omap4_pwrdm_operations);
 }
+
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 6/9] OMAP4: powerdomain data: add wake-up latency figures
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (10 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 6/9] OMAP4: " jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 7/9] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Vishwanath BS, Jean Pihet

From: Vishwanath BS <vishwanath.bs@ti.com>

This patch adds wake up latency numbers for OMAP4. Note that these are
preliminary numbers and need to be relooked.

Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>

The INACTIVE state is added as unsupported.

Tested on 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/powerdomains44xx_data.c |   85 +++++++++++++++++++++++++++
 1 files changed, 85 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index c4222c7..9b90d88 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -54,6 +54,13 @@ static struct powerdomain core_44xx_pwrdm = {
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -71,6 +78,13 @@ static struct powerdomain gfx_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* gfx_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.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,
+	},
 };
 
 /* abe_44xx_pwrdm: Audio back end power domain */
@@ -91,6 +105,13 @@ static struct powerdomain abe_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* periphmem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* dss_44xx_pwrdm: Display subsystem power domain */
@@ -109,6 +130,13 @@ static struct powerdomain dss_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* dss_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* tesla_44xx_pwrdm: Tesla processor power domain */
@@ -131,6 +159,13 @@ static struct powerdomain tesla_44xx_pwrdm = {
 		[2] = PWRSTS_ON,	/* tesla_l2 */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* wkup_44xx_pwrdm: Wake-up power domain */
@@ -164,6 +199,13 @@ static struct powerdomain cpu0_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu0_l1 */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -181,6 +223,13 @@ static struct powerdomain cpu1_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu1_l1 */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* emu_44xx_pwrdm: Emulation power domain */
@@ -218,6 +267,13 @@ static struct powerdomain mpu_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* mpu_l2 */
 		[2] = PWRSTS_ON,	/* mpu_ram */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* ivahd_44xx_pwrdm: IVA-HD power domain */
@@ -242,6 +298,13 @@ static struct powerdomain ivahd_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* tcm2_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* cam_44xx_pwrdm: Camera subsystem power domain */
@@ -259,6 +322,13 @@ static struct powerdomain cam_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* cam_mem */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.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,
+	},
 };
 
 /* l3init_44xx_pwrdm: L3 initators pheripherals power domain  */
@@ -277,6 +347,13 @@ static struct powerdomain l3init_44xx_pwrdm = {
 		[0] = PWRSTS_ON,	/* l3init_bank1 */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /* l4per_44xx_pwrdm: Target peripherals power domain */
@@ -297,6 +374,13 @@ static struct powerdomain l4per_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* retained_bank */
 	},
 	.flags		= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_OSWR] = 600,
+		[PWRDM_FUNC_PWRST_CSWR] = 300,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -353,3 +437,4 @@ void __init omap44xx_powerdomains_init(void)
 {
 	pwrdm_init(powerdomains_omap44xx, &omap4_pwrdm_operations);
 }
+
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 7/9] OMAP2+: omap_hwmod: manage the wake-up latency constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (12 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 7/9] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 293fa6c..69fa946 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -142,6 +142,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"
@@ -2322,11 +2323,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 1adea9c..bf9e81d 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -598,6 +598,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] 37+ messages in thread

* [RFC/PATCH 7/9] OMAP2+: omap_hwmod: manage the wake-up latency constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (11 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 293fa6c..69fa946 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -142,6 +142,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"
@@ -2322,11 +2323,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 1adea9c..bf9e81d 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -598,6 +598,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] 37+ messages in thread

* [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (13 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Implement the devices wake-up latency constraints using a 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/mach-omap2/pm.h                  |   17 +++-
 arch/arm/plat-omap/include/plat/omap-pm.h |  128 ----------------------
 arch/arm/plat-omap/omap-pm-constraints.c  |  169 +++++++++++++----------------
 arch/arm/plat-omap/omap-pm-noop.c         |   89 ---------------
 4 files changed, 90 insertions(+), 313 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 45bcfce..6fc6128 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)
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index c0a7520..4318a2d 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -70,136 +70,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..4b508c4 100644
--- a/arch/arm/plat-omap/omap-pm-constraints.c
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -17,132 +17,105 @@
 #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_params.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 _pm_qos_dev_wakeup_latency_handler(struct notifier_block *,
+					      unsigned long, void *);
+static struct notifier_block _pm_qos_dev_wakeup_latency_notifier = {
+	.notifier_call	= _pm_qos_dev_wakeup_latency_handler,
+};
 
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+
+static int _apply_dev_wakeup_constraint(void *req, unsigned long new_value)
 {
-	if (!dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	struct pm_qos_request_list *pm_qos_req = req;
+
+	/* Look for the platform device for the constraint target device */
+	pdev = to_platform_device(pm_qos_req->dev);
+
+	/* Try to catch non platform devices */
+	if (pdev->name == NULL) {
+		pr_err("%s: Error: platform device for device %s not valid\n",
+		       __func__, dev_name(pm_qos_req->dev));
 		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);
+	/* Find the associated omap_device for dev */
+	od = container_of(pdev, struct omap_device, pdev);
+	if (!od || (od->hwmods_cnt != 1)) {
+		pr_err("%s: Error: No unique hwmod for device %s\n",
+		       __func__, dev_name(pm_qos_req->dev));
+		return -EINVAL;
+	}
 
-	/*
-	 * 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.
-	 */
+	/* Find the primary omap_hwmod for dev */
+	oh = od->hwmods[0];
 
-	return 0;
+	/* Apply the constraint */
+	return omap_hwmod_set_wkup_lat_constraint(oh, pm_qos_req, new_value);
 }
 
-int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+/* PM QoS classes handlers */
+static int _pm_qos_dev_wakeup_latency_handler(struct notifier_block *nb,
+					      unsigned long new_value,
+					      void *req)
 {
-	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;
+	return _apply_dev_wakeup_constraint(req, new_value);
 }
 
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, 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 (!req_dev || !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 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.
+	 * A value of r == 0 removes the constraint. Convert it to the
+	 * generic _set_dev_constraint convention (-1 for constraint removal)
 	 */
-
-	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));
+	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;
 }
@@ -353,7 +326,15 @@ int __init omap_pm_if_early_init(void)
 /* Must be called after clock framework is initialized */
 int __init omap_pm_if_init(void)
 {
-	return 0;
+	int ret;
+
+	ret = pm_qos_add_notifier(PM_QOS_DEV_WAKEUP_LATENCY,
+				  &_pm_qos_dev_wakeup_latency_notifier);
+	if (ret)
+		WARN(1, KERN_ERR "Cannot add notifier for "
+			"PM_QOS_DEV_WAKEUP_LATENCY\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] 37+ messages in thread

* [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (14 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-27 18:33   ` Todd Poynor
  2011-06-27 18:33   ` Todd Poynor
  2011-06-24 14:38 ` [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state jean.pihet
                   ` (5 subsequent siblings)
  21 siblings, 2 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

Implement the devices wake-up latency constraints using a 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/mach-omap2/pm.h                  |   17 +++-
 arch/arm/plat-omap/include/plat/omap-pm.h |  128 ----------------------
 arch/arm/plat-omap/omap-pm-constraints.c  |  169 +++++++++++++----------------
 arch/arm/plat-omap/omap-pm-noop.c         |   89 ---------------
 4 files changed, 90 insertions(+), 313 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 45bcfce..6fc6128 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)
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index c0a7520..4318a2d 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -70,136 +70,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..4b508c4 100644
--- a/arch/arm/plat-omap/omap-pm-constraints.c
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -17,132 +17,105 @@
 #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_params.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 _pm_qos_dev_wakeup_latency_handler(struct notifier_block *,
+					      unsigned long, void *);
+static struct notifier_block _pm_qos_dev_wakeup_latency_notifier = {
+	.notifier_call	= _pm_qos_dev_wakeup_latency_handler,
+};
 
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+
+static int _apply_dev_wakeup_constraint(void *req, unsigned long new_value)
 {
-	if (!dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	struct pm_qos_request_list *pm_qos_req = req;
+
+	/* Look for the platform device for the constraint target device */
+	pdev = to_platform_device(pm_qos_req->dev);
+
+	/* Try to catch non platform devices */
+	if (pdev->name == NULL) {
+		pr_err("%s: Error: platform device for device %s not valid\n",
+		       __func__, dev_name(pm_qos_req->dev));
 		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);
+	/* Find the associated omap_device for dev */
+	od = container_of(pdev, struct omap_device, pdev);
+	if (!od || (od->hwmods_cnt != 1)) {
+		pr_err("%s: Error: No unique hwmod for device %s\n",
+		       __func__, dev_name(pm_qos_req->dev));
+		return -EINVAL;
+	}
 
-	/*
-	 * 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.
-	 */
+	/* Find the primary omap_hwmod for dev */
+	oh = od->hwmods[0];
 
-	return 0;
+	/* Apply the constraint */
+	return omap_hwmod_set_wkup_lat_constraint(oh, pm_qos_req, new_value);
 }
 
-int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+/* PM QoS classes handlers */
+static int _pm_qos_dev_wakeup_latency_handler(struct notifier_block *nb,
+					      unsigned long new_value,
+					      void *req)
 {
-	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;
+	return _apply_dev_wakeup_constraint(req, new_value);
 }
 
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, 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 (!req_dev || !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 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.
+	 * A value of r == 0 removes the constraint. Convert it to the
+	 * generic _set_dev_constraint convention (-1 for constraint removal)
 	 */
-
-	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));
+	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;
 }
@@ -353,7 +326,15 @@ int __init omap_pm_if_early_init(void)
 /* Must be called after clock framework is initialized */
 int __init omap_pm_if_init(void)
 {
-	return 0;
+	int ret;
+
+	ret = pm_qos_add_notifier(PM_QOS_DEV_WAKEUP_LATENCY,
+				  &_pm_qos_dev_wakeup_latency_notifier);
+	if (ret)
+		WARN(1, KERN_ERR "Cannot add notifier for "
+			"PM_QOS_DEV_WAKEUP_LATENCY\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] 37+ messages in thread

* [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (15 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-24 14:38 ` jean.pihet
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
via the device 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 +++++++++++-------------------------
 1 files changed, 13 insertions(+), 29 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)) {
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (16 preceding siblings ...)
  2011-06-24 14:38 ` [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state jean.pihet
@ 2011-06-24 14:38 ` jean.pihet
  2011-06-25 13:23   ` Santosh Shilimkar
  2011-06-25 13:23   ` Santosh Shilimkar
  2011-06-24 15:30 ` [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (3 subsequent siblings)
  21 siblings, 2 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
via the device 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 +++++++++++-------------------------
 1 files changed, 13 insertions(+), 29 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)) {
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (17 preceding siblings ...)
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-24 15:30 ` jean.pihet
  2011-06-24 15:30 ` jean.pihet
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 15:30 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

This patch set is in an RFC state, for review and comments.

In order to implement the new class in PM QoS the following changes have been
made:

1. Add a new PM QoS class for device wake-up constraints
(PM_QOS_DEV_WAKEUP_LATENCY).
Due to the per-device nature of the new class the constraints lists are stored
inside the device dev_pm_info struct instead of the internal per-class
constraints lists.
The new class is only available from kernel drivers and so is not exported to
user space.

2. Make the pm_qos_add_request API more generic by using a
struct pm_qos_parameters parameter. This allows easy extension in the future.

3. Upon a change of the strongest constraint in the PM_QOS_DEV_WAKEUP_LATENCY
class a notification chain mechanism is used to take action on the system.
This is the proposed way to have PM QoS and the platform dependant code to
interact with each other, cf. 4 below.
The notification mechanism now passes the constraint request struct ptr in
order for the notifier callback to have access to the full set of constraint
data, e.g. the struct device ptr.

4. cpuidle interaction with the OMAP3 cpuidle handler
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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via the device
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.

5. Update the pm_qos_add_request callers to the generic API

6. Minor clean-ups and rename of struct fields

Questions:
1. How to retrieve the device ptr from a given device driver in order to add
a constraint on it?
2. The device struct has recently been extended with the power domain
information. Can this be used to apply the constraints on power domains?

On-going developments, patches in preparation:
1. write Documentation for the new PM QoS class
2. validate the constraints framework on OMAP3&4 HW
3. refine the power domains wake-up latency and the cpuidle figures

Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile
tested only using OMAP and x86 generic defconfigs.


Jean Pihet (8):
  PM: add a per-device wake-up latency constraints plist
  PM: extend PM QoS with per-device wake-up 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

Vishwanath BS (1):
  OMAP4: powerdomain data: add wake-up latency figures

 arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
 arch/arm/mach-omap2/pm.h                     |   17 ++-
 arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
 arch/arm/mach-omap2/powerdomain.h            |   33 +++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
 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     |  344 ++++++++++++++++++++++++++
 arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
 drivers/base/power/main.c                    |    1 +
 drivers/i2c/busses/i2c-omap.c                |   35 ++-
 drivers/media/video/via-camera.c             |    5 +-
 drivers/net/e1000e/netdev.c                  |    9 +-
 drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
 include/linux/pm.h                           |    2 +
 include/linux/pm_qos_params.h                |   40 ++--
 kernel/pm_qos_params.c                       |  142 ++++++-----
 sound/core/pcm_native.c                      |    8 +-
 23 files changed, 939 insertions(+), 367 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (18 preceding siblings ...)
  2011-06-24 15:30 ` [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
@ 2011-06-24 15:30 ` jean.pihet
  2011-06-27 13:40 ` [linux-pm] " mark gross
  2011-06-27 13:40 ` mark gross
  21 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 15:30 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

This patch set is in an RFC state, for review and comments.

In order to implement the new class in PM QoS the following changes have been
made:

1. Add a new PM QoS class for device wake-up constraints
(PM_QOS_DEV_WAKEUP_LATENCY).
Due to the per-device nature of the new class the constraints lists are stored
inside the device dev_pm_info struct instead of the internal per-class
constraints lists.
The new class is only available from kernel drivers and so is not exported to
user space.

2. Make the pm_qos_add_request API more generic by using a
struct pm_qos_parameters parameter. This allows easy extension in the future.

3. Upon a change of the strongest constraint in the PM_QOS_DEV_WAKEUP_LATENCY
class a notification chain mechanism is used to take action on the system.
This is the proposed way to have PM QoS and the platform dependant code to
interact with each other, cf. 4 below.
The notification mechanism now passes the constraint request struct ptr in
order for the notifier callback to have access to the full set of constraint
data, e.g. the struct device ptr.

4. cpuidle interaction with the OMAP3 cpuidle handler
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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via the device
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.

5. Update the pm_qos_add_request callers to the generic API

6. Minor clean-ups and rename of struct fields

Questions:
1. How to retrieve the device ptr from a given device driver in order to add
a constraint on it?
2. The device struct has recently been extended with the power domain
information. Can this be used to apply the constraints on power domains?

On-going developments, patches in preparation:
1. write Documentation for the new PM QoS class
2. validate the constraints framework on OMAP3&4 HW
3. refine the power domains wake-up latency and the cpuidle figures

Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile
tested only using OMAP and x86 generic defconfigs.


Jean Pihet (8):
  PM: add a per-device wake-up latency constraints plist
  PM: extend PM QoS with per-device wake-up 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

Vishwanath BS (1):
  OMAP4: powerdomain data: add wake-up latency figures

 arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
 arch/arm/mach-omap2/pm.h                     |   17 ++-
 arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
 arch/arm/mach-omap2/powerdomain.h            |   33 +++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
 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     |  344 ++++++++++++++++++++++++++
 arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
 drivers/base/power/main.c                    |    1 +
 drivers/i2c/busses/i2c-omap.c                |   35 ++-
 drivers/media/video/via-camera.c             |    5 +-
 drivers/net/e1000e/netdev.c                  |    9 +-
 drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
 include/linux/pm.h                           |    2 +
 include/linux/pm_qos_params.h                |   40 ++--
 kernel/pm_qos_params.c                       |  142 ++++++-----
 sound/core/pcm_native.c                      |    8 +-
 23 files changed, 939 insertions(+), 367 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

-- 
1.7.4.1


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-24 14:38 ` jean.pihet
  2011-06-25 13:23   ` Santosh Shilimkar
@ 2011-06-25 13:23   ` Santosh Shilimkar
  1 sibling, 0 replies; 37+ messages in thread
From: Santosh Shilimkar @ 2011-06-25 13:23 UTC (permalink / raw)
  To: jean.pihet; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet<j-pihet@ti.com>
>
> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
> via the device 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.
>
With above comment, I was expecting that the latency numbers
in the table will change.

> 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 +++++++++++-------------------------
>   1 files changed, 13 insertions(+), 29 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},

Latency numbers still seems to include CORE PD latency as
well. Am I missing something Jean?

Regards
Santosh

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-25 13:23   ` Santosh Shilimkar
  2011-06-27  6:53     ` Jean Pihet
  2011-06-25 13:23   ` Santosh Shilimkar
  1 sibling, 1 reply; 37+ messages in thread
From: Santosh Shilimkar @ 2011-06-25 13:23 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet<j-pihet@ti.com>
>
> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
> via the device 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.
>
With above comment, I was expecting that the latency numbers
in the table will change.

> 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 +++++++++++-------------------------
>   1 files changed, 13 insertions(+), 29 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},

Latency numbers still seems to include CORE PD latency as
well. Am I missing something Jean?

Regards
Santosh

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-25 13:23   ` Santosh Shilimkar
@ 2011-06-27  6:53     ` Jean Pihet
  2011-06-27 14:11       ` Santosh Shilimkar
  2011-06-27 14:11       ` Santosh Shilimkar
  0 siblings, 2 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-27  6:53 UTC (permalink / raw)
  To: Santosh Shilimkar; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

Hi Santosh,

On Sat, Jun 25, 2011 at 3:23 PM, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
> On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
>>
>> From: Jean Pihet<j-pihet@ti.com>
>>
>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
>> via the device 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.
>>
> With above comment, I was expecting that the latency numbers
> in the table will change.
Not necessarily. I just wanted to have it clearly stated in the commit
description.
In any case I will review the figures and update them if needed.
...

>>  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},
>
> Latency numbers still seems to include CORE PD latency as
> well. Am I missing something Jean?
The figures are looking OK.

Thanks,
Jean

>
> Regards
> Santosh
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (20 preceding siblings ...)
  2011-06-27 13:40 ` [linux-pm] " mark gross
@ 2011-06-27 13:40 ` mark gross
  21 siblings, 0 replies; 37+ messages in thread
From: mark gross @ 2011-06-27 13:40 UTC (permalink / raw)
  To: jean.pihet; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jun 24, 2011 at 04:37:57PM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> This patch set is in an RFC state, for review and comments.
> 
> In order to implement the new class in PM QoS the following changes
> have been made:
> 
> 1. Add a new PM QoS class for device wake-up constraints
> (PM_QOS_DEV_WAKEUP_LATENCY).  Due to the per-device nature of the new
> class the constraints lists are stored inside the device dev_pm_info
> struct instead of the internal per-class constraints lists.  The new
> class is only available from kernel drivers and so is not exported to
> user space.

I have not looked at the patch yet but, this reads like "add a
constraint class per LDM device in the current os"  I assume it would
add and destroy them with driver load / unloads.  I wonder how that
would work in practice.  Probubly need an notifier or a silent failure
for constraint dependents  with stale refs to the device.

Historically, I had initially implemented pm_qos to support dynamic
creation of constraint classes.  But, the feedback I got on that was
that "we can't trust driver writers" so lets not enable that.  Perhaps
keeping such constraints not exposed to user mode gets around the
objection we had back then.

> 
> 2. Make the pm_qos_add_request API more generic by using a struct
> pm_qos_parameters parameter. This allows easy extension in the future.
> 
> 3. Upon a change of the strongest constraint in the
> PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used

strongest constraint?  Do you mean the aggregated constraint?

> to take action on the system. This is the proposed way to have PM QoS
> and the platform dependant code to interact with each other, cf. 4
> below.  The notification mechanism now passes the constraint request
> struct ptr in order for the notifier callback to have access to the
> full set of constraint data, e.g. the struct device ptr.
> 
> 4. cpuidle interaction with the OMAP3 cpuidle handler
> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via
> the device 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.
> 
> 5. Update the pm_qos_add_request callers to the generic API
> 
> 6. Minor clean-ups and rename of struct fields
> 
> Questions:
> 1. How to retrieve the device ptr from a given device driver in order
> to add a constraint on it?
put the pm_qos constraint class data into the LDM so all devices
implicitly have a constraint class associated with each is my first
thought.  Of course you still have the problem of one driver getting the
handle to the constraint class of some other driver.  hmmm that is a
messy problem.

Might not be a popular idea...

I'll look at the patch details and have more thoughts on this soon.

--mark
> 2. The device struct has been extended with the power domain
> information. Can this be used to apply the constraints on power
> domains, as proposed by [1]?
> 
> On-going developments, patches in preparation:
> 1. write Documentation for the new PM QoS class
> 2. validate the constraints framework on OMAP3&4
> 3. refine the power domains wake-up latency and the cpuidle figures
> 
> [1] http://marc.info/?l=linux-omap&m=130451613408148&w=2
> 
> Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.
> 
> 
> Jean Pihet (8):
>   PM: add a per-device wake-up latency constraints plist
>   PM: extend PM QoS with per-device wake-up 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
> 
> Vishwanath BS (1):
>   OMAP4: powerdomain data: add wake-up latency figures
> 
>  arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
>  arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
>  arch/arm/mach-omap2/pm.h                     |   17 ++-
>  arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
>  arch/arm/mach-omap2/powerdomain.h            |   33 +++-
>  arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
>  arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
>  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     |  344 ++++++++++++++++++++++++++
>  arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
>  drivers/base/power/main.c                    |    1 +
>  drivers/i2c/busses/i2c-omap.c                |   35 ++-
>  drivers/media/video/via-camera.c             |    5 +-
>  drivers/net/e1000e/netdev.c                  |    9 +-
>  drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
>  include/linux/pm.h                           |    2 +
>  include/linux/pm_qos_params.h                |   40 ++--
>  kernel/pm_qos_params.c                       |  142 ++++++-----
>  sound/core/pcm_native.c                      |    8 +-
>  23 files changed, 939 insertions(+), 367 deletions(-)
>  create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
> 
> -- 
> 1.7.4.1
> 
> _______________________________________________
> linux-pm mailing list
> linux-pm@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [linux-pm] [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
                   ` (19 preceding siblings ...)
  2011-06-24 15:30 ` jean.pihet
@ 2011-06-27 13:40 ` mark gross
  2011-06-30 15:07   ` Jean Pihet
  2011-06-30 15:07   ` Jean Pihet
  2011-06-27 13:40 ` mark gross
  21 siblings, 2 replies; 37+ messages in thread
From: mark gross @ 2011-06-27 13:40 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jun 24, 2011 at 04:37:57PM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> This patch set is in an RFC state, for review and comments.
> 
> In order to implement the new class in PM QoS the following changes
> have been made:
> 
> 1. Add a new PM QoS class for device wake-up constraints
> (PM_QOS_DEV_WAKEUP_LATENCY).  Due to the per-device nature of the new
> class the constraints lists are stored inside the device dev_pm_info
> struct instead of the internal per-class constraints lists.  The new
> class is only available from kernel drivers and so is not exported to
> user space.

I have not looked at the patch yet but, this reads like "add a
constraint class per LDM device in the current os"  I assume it would
add and destroy them with driver load / unloads.  I wonder how that
would work in practice.  Probubly need an notifier or a silent failure
for constraint dependents  with stale refs to the device.

Historically, I had initially implemented pm_qos to support dynamic
creation of constraint classes.  But, the feedback I got on that was
that "we can't trust driver writers" so lets not enable that.  Perhaps
keeping such constraints not exposed to user mode gets around the
objection we had back then.

> 
> 2. Make the pm_qos_add_request API more generic by using a struct
> pm_qos_parameters parameter. This allows easy extension in the future.
> 
> 3. Upon a change of the strongest constraint in the
> PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used

strongest constraint?  Do you mean the aggregated constraint?

> to take action on the system. This is the proposed way to have PM QoS
> and the platform dependant code to interact with each other, cf. 4
> below.  The notification mechanism now passes the constraint request
> struct ptr in order for the notifier callback to have access to the
> full set of constraint data, e.g. the struct device ptr.
> 
> 4. cpuidle interaction with the OMAP3 cpuidle handler
> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via
> the device 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.
> 
> 5. Update the pm_qos_add_request callers to the generic API
> 
> 6. Minor clean-ups and rename of struct fields
> 
> Questions:
> 1. How to retrieve the device ptr from a given device driver in order
> to add a constraint on it?
put the pm_qos constraint class data into the LDM so all devices
implicitly have a constraint class associated with each is my first
thought.  Of course you still have the problem of one driver getting the
handle to the constraint class of some other driver.  hmmm that is a
messy problem.

Might not be a popular idea...

I'll look at the patch details and have more thoughts on this soon.

--mark
> 2. The device struct has been extended with the power domain
> information. Can this be used to apply the constraints on power
> domains, as proposed by [1]?
> 
> On-going developments, patches in preparation:
> 1. write Documentation for the new PM QoS class
> 2. validate the constraints framework on OMAP3&4
> 3. refine the power domains wake-up latency and the cpuidle figures
> 
> [1] http://marc.info/?l=linux-omap&m=130451613408148&w=2
> 
> Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.
> 
> 
> Jean Pihet (8):
>   PM: add a per-device wake-up latency constraints plist
>   PM: extend PM QoS with per-device wake-up 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
> 
> Vishwanath BS (1):
>   OMAP4: powerdomain data: add wake-up latency figures
> 
>  arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
>  arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
>  arch/arm/mach-omap2/pm.h                     |   17 ++-
>  arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
>  arch/arm/mach-omap2/powerdomain.h            |   33 +++-
>  arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
>  arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
>  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     |  344 ++++++++++++++++++++++++++
>  arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
>  drivers/base/power/main.c                    |    1 +
>  drivers/i2c/busses/i2c-omap.c                |   35 ++-
>  drivers/media/video/via-camera.c             |    5 +-
>  drivers/net/e1000e/netdev.c                  |    9 +-
>  drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
>  include/linux/pm.h                           |    2 +
>  include/linux/pm_qos_params.h                |   40 ++--
>  kernel/pm_qos_params.c                       |  142 ++++++-----
>  sound/core/pcm_native.c                      |    8 +-
>  23 files changed, 939 insertions(+), 367 deletions(-)
>  create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
> 
> -- 
> 1.7.4.1
> 
> _______________________________________________
> linux-pm mailing list
> linux-pm@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/linux-pm

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-27  6:53     ` Jean Pihet
  2011-06-27 14:11       ` Santosh Shilimkar
@ 2011-06-27 14:11       ` Santosh Shilimkar
  1 sibling, 0 replies; 37+ messages in thread
From: Santosh Shilimkar @ 2011-06-27 14:11 UTC (permalink / raw)
  To: Jean Pihet; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

On 6/26/2011 11:53 PM, Jean Pihet wrote:
> Hi Santosh,
>
> On Sat, Jun 25, 2011 at 3:23 PM, Santosh Shilimkar
> <santosh.shilimkar@ti.com>  wrote:
>> On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
>>>
>>> From: Jean Pihet<j-pihet@ti.com>
>>>
>>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
>>> via the device 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.
>>>
>> With above comment, I was expecting that the latency numbers
>> in the table will change.
> Not necessarily. I just wanted to have it clearly stated in the commit
> description.
> In any case I will review the figures and update them if needed.
> ...
>
>>>   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},
>>
>> Latency numbers still seems to include CORE PD latency as
>> well. Am I missing something Jean?
> The figures are looking OK.
>
Hmmm...
Well they represent mostly MPU + CORE PD sleep + wakeup latencies
I suppose so not sure what you mean by OK here.

Regards
Santosh

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-27  6:53     ` Jean Pihet
@ 2011-06-27 14:11       ` Santosh Shilimkar
  2011-06-27 14:31         ` Jean Pihet
  2011-06-27 14:31         ` Jean Pihet
  2011-06-27 14:11       ` Santosh Shilimkar
  1 sibling, 2 replies; 37+ messages in thread
From: Santosh Shilimkar @ 2011-06-27 14:11 UTC (permalink / raw)
  To: Jean Pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

On 6/26/2011 11:53 PM, Jean Pihet wrote:
> Hi Santosh,
>
> On Sat, Jun 25, 2011 at 3:23 PM, Santosh Shilimkar
> <santosh.shilimkar@ti.com>  wrote:
>> On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
>>>
>>> From: Jean Pihet<j-pihet@ti.com>
>>>
>>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
>>> via the device 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.
>>>
>> With above comment, I was expecting that the latency numbers
>> in the table will change.
> Not necessarily. I just wanted to have it clearly stated in the commit
> description.
> In any case I will review the figures and update them if needed.
> ...
>
>>>   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},
>>
>> Latency numbers still seems to include CORE PD latency as
>> well. Am I missing something Jean?
> The figures are looking OK.
>
Hmmm...
Well they represent mostly MPU + CORE PD sleep + wakeup latencies
I suppose so not sure what you mean by OK here.

Regards
Santosh

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-27 14:11       ` Santosh Shilimkar
@ 2011-06-27 14:31         ` Jean Pihet
  2011-06-27 14:31         ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-27 14:31 UTC (permalink / raw)
  To: Santosh Shilimkar; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

Santosh,

On Mon, Jun 27, 2011 at 4:11 PM, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
> On 6/26/2011 11:53 PM, Jean Pihet wrote:
>>
>> Hi Santosh,
>>
>> On Sat, Jun 25, 2011 at 3:23 PM, Santosh Shilimkar
>> <santosh.shilimkar@ti.com>  wrote:
>>>
>>> On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
>>>>
>>>> From: Jean Pihet<j-pihet@ti.com>
>>>>
>>>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
>>>> via the device 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.
>>>>
>>> With above comment, I was expecting that the latency numbers
>>> in the table will change.
>>
>> Not necessarily. I just wanted to have it clearly stated in the commit
>> description.
>> In any case I will review the figures and update them if needed.
>> ...
>>
>>>>  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},
>>>
>>> Latency numbers still seems to include CORE PD latency as
>>> well. Am I missing something Jean?
>>
>> The figures are looking OK.
>>
> Hmmm...
> Well they represent mostly MPU + CORE PD sleep + wakeup latencies
> I suppose so not sure what you mean by OK here.
I mean the figures are representing what they are supposed to. As said
above they might need refining.

Thanks,
Jean

>
> Regards
> Santosh
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state
  2011-06-27 14:11       ` Santosh Shilimkar
  2011-06-27 14:31         ` Jean Pihet
@ 2011-06-27 14:31         ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-27 14:31 UTC (permalink / raw)
  To: Santosh Shilimkar
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

Santosh,

On Mon, Jun 27, 2011 at 4:11 PM, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
> On 6/26/2011 11:53 PM, Jean Pihet wrote:
>>
>> Hi Santosh,
>>
>> On Sat, Jun 25, 2011 at 3:23 PM, Santosh Shilimkar
>> <santosh.shilimkar@ti.com>  wrote:
>>>
>>> On 6/24/2011 7:38 AM, jean.pihet@newoldbits.com wrote:
>>>>
>>>> From: Jean Pihet<j-pihet@ti.com>
>>>>
>>>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework,
>>>> via the device 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.
>>>>
>>> With above comment, I was expecting that the latency numbers
>>> in the table will change.
>>
>> Not necessarily. I just wanted to have it clearly stated in the commit
>> description.
>> In any case I will review the figures and update them if needed.
>> ...
>>
>>>>  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},
>>>
>>> Latency numbers still seems to include CORE PD latency as
>>> well. Am I missing something Jean?
>>
>> The figures are looking OK.
>>
> Hmmm...
> Well they represent mostly MPU + CORE PD sleep + wakeup latencies
> I suppose so not sure what you mean by OK here.
I mean the figures are representing what they are supposed to. As said
above they might need refining.

Thanks,
Jean

>
> Regards
> Santosh
>
--
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] 37+ messages in thread

* Re: [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-24 14:38 ` jean.pihet
@ 2011-06-27 18:33   ` Todd Poynor
  2011-06-27 18:33   ` Todd Poynor
  1 sibling, 0 replies; 37+ messages in thread
From: Todd Poynor @ 2011-06-27 18:33 UTC (permalink / raw)
  To: jean.pihet; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jun 24, 2011 at 04:38:05PM +0200, jean.pihet@newoldbits.com wrote:
...
> +	/* Find the associated omap_device for dev */
> +	od = container_of(pdev, struct omap_device, pdev);
> +	if (!od || (od->hwmods_cnt != 1)) {
> +		pr_err("%s: Error: No unique hwmod for device %s\n",
> +		       __func__, dev_name(pm_qos_req->dev));
> +		return -EINVAL;

Check for !od can be dropped... if there's a check for !pdev needed
can add that, but container_of() won't return NULL for a valid
contained field.


Todd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-24 14:38 ` jean.pihet
  2011-06-27 18:33   ` Todd Poynor
@ 2011-06-27 18:33   ` Todd Poynor
  2011-06-30 15:08     ` Jean Pihet
  2011-06-30 15:08     ` Jean Pihet
  1 sibling, 2 replies; 37+ messages in thread
From: Todd Poynor @ 2011-06-27 18:33 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jun 24, 2011 at 04:38:05PM +0200, jean.pihet@newoldbits.com wrote:
...
> +	/* Find the associated omap_device for dev */
> +	od = container_of(pdev, struct omap_device, pdev);
> +	if (!od || (od->hwmods_cnt != 1)) {
> +		pr_err("%s: Error: No unique hwmod for device %s\n",
> +		       __func__, dev_name(pm_qos_req->dev));
> +		return -EINVAL;

Check for !od can be dropped... if there's a check for !pdev needed
can add that, but container_of() won't return NULL for a valid
contained field.


Todd

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-27 13:40 ` [linux-pm] " mark gross
  2011-06-30 15:07   ` Jean Pihet
@ 2011-06-30 15:07   ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-30 15:07 UTC (permalink / raw)
  To: markgross; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

Hi Mark,

On Mon, Jun 27, 2011 at 3:40 PM, mark gross <markgross@thegnar.org> wrote:
> On Fri, Jun 24, 2011 at 04:37:57PM +0200, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> This patch set is in an RFC state, for review and comments.
>>
>> In order to implement the new class in PM QoS the following changes
>> have been made:
>>
>> 1. Add a new PM QoS class for device wake-up constraints
>> (PM_QOS_DEV_WAKEUP_LATENCY).  Due to the per-device nature of the new
>> class the constraints lists are stored inside the device dev_pm_info
>> struct instead of the internal per-class constraints lists.  The new
>> class is only available from kernel drivers and so is not exported to
>> user space.
>
> I have not looked at the patch yet but, this reads like "add a
> constraint class per LDM device in the current os"  I assume it would
> add and destroy them with driver load / unloads.  I wonder how that
> would work in practice.  Probubly need an notifier or a silent failure
> for constraint dependents  with stale refs to the device.
I have added a notification from the device PM framework to PM QoS, in
order to support the dynamic insertion and removal of the devices.
This code is in RFC state (currently untested with dynamic device
insertion and removal), for comments and review.

>
> Historically, I had initially implemented pm_qos to support dynamic
> creation of constraint classes.  But, the feedback I got on that was
> that "we can't trust driver writers" so lets not enable that.
The drivers only need to care about allocating a constraint request
and calling the PM QoS API. Cf. PATCH 02/11 for examples of the calls.

> Perhaps
> keeping such constraints not exposed to user mode gets around the
> objection we had back then.

>
>>
>> 2. Make the pm_qos_add_request API more generic by using a struct
>> pm_qos_parameters parameter. This allows easy extension in the future.
>>
>> 3. Upon a change of the strongest constraint in the
>> PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used
>
> strongest constraint?  Do you mean the aggregated constraint?
Yes. The 'strongest' constraint is the one that needs to be notified
to the low level code.

>
>> to take action on the system. This is the proposed way to have PM QoS
>> and the platform dependant code to interact with each other, cf. 4
>> below.  The notification mechanism now passes the constraint request
>> struct ptr in order for the notifier callback to have access to the
>> full set of constraint data, e.g. the struct device ptr.
>>
>> 4. cpuidle interaction with the OMAP3 cpuidle handler
>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via
>> the device 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.
>>
>> 5. Update the pm_qos_add_request callers to the generic API
>>
>> 6. Minor clean-ups and rename of struct fields
>>
>> Questions:
>> 1. How to retrieve the device ptr from a given device driver in order
>> to add a constraint on it?
> put the pm_qos constraint class data into the LDM so all devices
> implicitly have a constraint class associated with each is my first
> thought.  Of course you still have the problem of one driver getting the
> handle to the constraint class of some other driver.  hmmm that is a
> messy problem.
Indeed. OMAP code has calls such as 'omap2_get_mpuss_device' which
return the MPU dev.

>
> Might not be a popular idea...
>
> I'll look at the patch details and have more thoughts on this soon.
OK, thank you for the reply.

The patch set has been updated to v2, submission coming soon.

Regards,
Jean

>
> --mark
>> 2. The device struct has been extended with the power domain
>> information. Can this be used to apply the constraints on power
>> domains, as proposed by [1]?
>>
>> On-going developments, patches in preparation:
>> 1. write Documentation for the new PM QoS class
>> 2. validate the constraints framework on OMAP3&4
>> 3. refine the power domains wake-up latency and the cpuidle figures
>>
>> [1] http://marc.info/?l=linux-omap&m=130451613408148&w=2
>>
>> Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.
>>
>>
>> Jean Pihet (8):
>>   PM: add a per-device wake-up latency constraints plist
>>   PM: extend PM QoS with per-device wake-up 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
>>
>> Vishwanath BS (1):
>>   OMAP4: powerdomain data: add wake-up latency figures
>>
>>  arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
>>  arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
>>  arch/arm/mach-omap2/pm.h                     |   17 ++-
>>  arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
>>  arch/arm/mach-omap2/powerdomain.h            |   33 +++-
>>  arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
>>  arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
>>  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     |  344 ++++++++++++++++++++++++++
>>  arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
>>  drivers/base/power/main.c                    |    1 +
>>  drivers/i2c/busses/i2c-omap.c                |   35 ++-
>>  drivers/media/video/via-camera.c             |    5 +-
>>  drivers/net/e1000e/netdev.c                  |    9 +-
>>  drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
>>  include/linux/pm.h                           |    2 +
>>  include/linux/pm_qos_params.h                |   40 ++--
>>  kernel/pm_qos_params.c                       |  142 ++++++-----
>>  sound/core/pcm_native.c                      |    8 +-
>>  23 files changed, 939 insertions(+), 367 deletions(-)
>>  create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
>>
>> --
>> 1.7.4.1
>>
>> _______________________________________________
>> linux-pm mailing list
>> linux-pm@lists.linux-foundation.org
>> https://lists.linux-foundation.org/mailman/listinfo/linux-pm
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [linux-pm] [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
  2011-06-27 13:40 ` [linux-pm] " mark gross
@ 2011-06-30 15:07   ` Jean Pihet
  2011-06-30 15:07   ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-30 15:07 UTC (permalink / raw)
  To: markgross
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

Hi Mark,

On Mon, Jun 27, 2011 at 3:40 PM, mark gross <markgross@thegnar.org> wrote:
> On Fri, Jun 24, 2011 at 04:37:57PM +0200, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> This patch set is in an RFC state, for review and comments.
>>
>> In order to implement the new class in PM QoS the following changes
>> have been made:
>>
>> 1. Add a new PM QoS class for device wake-up constraints
>> (PM_QOS_DEV_WAKEUP_LATENCY).  Due to the per-device nature of the new
>> class the constraints lists are stored inside the device dev_pm_info
>> struct instead of the internal per-class constraints lists.  The new
>> class is only available from kernel drivers and so is not exported to
>> user space.
>
> I have not looked at the patch yet but, this reads like "add a
> constraint class per LDM device in the current os"  I assume it would
> add and destroy them with driver load / unloads.  I wonder how that
> would work in practice.  Probubly need an notifier or a silent failure
> for constraint dependents  with stale refs to the device.
I have added a notification from the device PM framework to PM QoS, in
order to support the dynamic insertion and removal of the devices.
This code is in RFC state (currently untested with dynamic device
insertion and removal), for comments and review.

>
> Historically, I had initially implemented pm_qos to support dynamic
> creation of constraint classes.  But, the feedback I got on that was
> that "we can't trust driver writers" so lets not enable that.
The drivers only need to care about allocating a constraint request
and calling the PM QoS API. Cf. PATCH 02/11 for examples of the calls.

> Perhaps
> keeping such constraints not exposed to user mode gets around the
> objection we had back then.

>
>>
>> 2. Make the pm_qos_add_request API more generic by using a struct
>> pm_qos_parameters parameter. This allows easy extension in the future.
>>
>> 3. Upon a change of the strongest constraint in the
>> PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used
>
> strongest constraint?  Do you mean the aggregated constraint?
Yes. The 'strongest' constraint is the one that needs to be notified
to the low level code.

>
>> to take action on the system. This is the proposed way to have PM QoS
>> and the platform dependant code to interact with each other, cf. 4
>> below.  The notification mechanism now passes the constraint request
>> struct ptr in order for the notifier callback to have access to the
>> full set of constraint data, e.g. the struct device ptr.
>>
>> 4. cpuidle interaction with the OMAP3 cpuidle handler
>> 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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via
>> the device 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.
>>
>> 5. Update the pm_qos_add_request callers to the generic API
>>
>> 6. Minor clean-ups and rename of struct fields
>>
>> Questions:
>> 1. How to retrieve the device ptr from a given device driver in order
>> to add a constraint on it?
> put the pm_qos constraint class data into the LDM so all devices
> implicitly have a constraint class associated with each is my first
> thought.  Of course you still have the problem of one driver getting the
> handle to the constraint class of some other driver.  hmmm that is a
> messy problem.
Indeed. OMAP code has calls such as 'omap2_get_mpuss_device' which
return the MPU dev.

>
> Might not be a popular idea...
>
> I'll look at the patch details and have more thoughts on this soon.
OK, thank you for the reply.

The patch set has been updated to v2, submission coming soon.

Regards,
Jean

>
> --mark
>> 2. The device struct has been extended with the power domain
>> information. Can this be used to apply the constraints on power
>> domains, as proposed by [1]?
>>
>> On-going developments, patches in preparation:
>> 1. write Documentation for the new PM QoS class
>> 2. validate the constraints framework on OMAP3&4
>> 3. refine the power domains wake-up latency and the cpuidle figures
>>
>> [1] http://marc.info/?l=linux-omap&m=130451613408148&w=2
>>
>> Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.
>>
>>
>> Jean Pihet (8):
>>   PM: add a per-device wake-up latency constraints plist
>>   PM: extend PM QoS with per-device wake-up 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
>>
>> Vishwanath BS (1):
>>   OMAP4: powerdomain data: add wake-up latency figures
>>
>>  arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
>>  arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
>>  arch/arm/mach-omap2/pm.h                     |   17 ++-
>>  arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
>>  arch/arm/mach-omap2/powerdomain.h            |   33 +++-
>>  arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
>>  arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
>>  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     |  344 ++++++++++++++++++++++++++
>>  arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
>>  drivers/base/power/main.c                    |    1 +
>>  drivers/i2c/busses/i2c-omap.c                |   35 ++-
>>  drivers/media/video/via-camera.c             |    5 +-
>>  drivers/net/e1000e/netdev.c                  |    9 +-
>>  drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
>>  include/linux/pm.h                           |    2 +
>>  include/linux/pm_qos_params.h                |   40 ++--
>>  kernel/pm_qos_params.c                       |  142 ++++++-----
>>  sound/core/pcm_native.c                      |    8 +-
>>  23 files changed, 939 insertions(+), 367 deletions(-)
>>  create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
>>
>> --
>> 1.7.4.1
>>
>> _______________________________________________
>> linux-pm mailing list
>> linux-pm@lists.linux-foundation.org
>> https://lists.linux-foundation.org/mailman/listinfo/linux-pm
>
--
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] 37+ messages in thread

* Re: [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-27 18:33   ` Todd Poynor
  2011-06-30 15:08     ` Jean Pihet
@ 2011-06-30 15:08     ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-30 15:08 UTC (permalink / raw)
  To: Todd Poynor; +Cc: Linux PM mailing list, linux-omap, Jean Pihet

On Mon, Jun 27, 2011 at 8:33 PM, Todd Poynor <toddpoynor@google.com> wrote:
> On Fri, Jun 24, 2011 at 04:38:05PM +0200, jean.pihet@newoldbits.com wrote:
> ...
>> +     /* Find the associated omap_device for dev */
>> +     od = container_of(pdev, struct omap_device, pdev);
>> +     if (!od || (od->hwmods_cnt != 1)) {
>> +             pr_err("%s: Error: No unique hwmod for device %s\n",
>> +                    __func__, dev_name(pm_qos_req->dev));
>> +             return -EINVAL;
>
> Check for !od can be dropped... if there's a check for !pdev needed
> can add that, but container_of() won't return NULL for a valid
> contained field.
Ok fixed in the v2 version.

Thanks!
Jean


>
>
> Todd
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-06-27 18:33   ` Todd Poynor
@ 2011-06-30 15:08     ` Jean Pihet
  2011-06-30 15:08     ` Jean Pihet
  1 sibling, 0 replies; 37+ messages in thread
From: Jean Pihet @ 2011-06-30 15:08 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, Jean Pihet

On Mon, Jun 27, 2011 at 8:33 PM, Todd Poynor <toddpoynor@google.com> wrote:
> On Fri, Jun 24, 2011 at 04:38:05PM +0200, jean.pihet@newoldbits.com wrote:
> ...
>> +     /* Find the associated omap_device for dev */
>> +     od = container_of(pdev, struct omap_device, pdev);
>> +     if (!od || (od->hwmods_cnt != 1)) {
>> +             pr_err("%s: Error: No unique hwmod for device %s\n",
>> +                    __func__, dev_name(pm_qos_req->dev));
>> +             return -EINVAL;
>
> Check for !od can be dropped... if there's a check for !pdev needed
> can add that, but container_of() won't return NULL for a valid
> contained field.
Ok fixed in the v2 version.

Thanks!
Jean


>
>
> Todd
>
--
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] 37+ messages in thread

* [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class
@ 2011-06-24 14:37 jean.pihet
  0 siblings, 0 replies; 37+ messages in thread
From: jean.pihet @ 2011-06-24 14:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list
  Cc: Jean Pihet

From: Jean Pihet <j-pihet@ti.com>

This patch set is in an RFC state, for review and comments.

In order to implement the new class in PM QoS the following changes have been made:

1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_WAKEUP_LATENCY).
Due to the per-device nature of the new class the constraints lists are stored inside the device dev_pm_info struct instead of the internal per-class constraints lists.
The new class is only available from kernel drivers and so is not exported to user space.

2. Make the pm_qos_add_request API more generic by using a struct pm_qos_parameters parameter. This allows easy extension in the future.

3. Upon a change of the strongest constraint in the PM_QOS_DEV_WAKEUP_LATENCY class a notification chain mechanism is used to take action on the system. This is the proposed way to have PM QoS and the platform dependant code to interact with each other, cf. 4 below.
The notification mechanism now passes the constraint request struct ptr in order for the notifier callback to have access to the full set of constraint data, e.g. the struct device ptr.

4. cpuidle interaction with the OMAP3 cpuidle handler
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 PM_QOS_DEV_WAKEUP_LATENCY class of the PM QoS framework, via the device 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.

5. Update the pm_qos_add_request callers to the generic API

6. Minor clean-ups and rename of struct fields

Questions:
1. How to retrieve the device ptr from a given device driver in order to add a constraint on it?
2. The device struct has been extended with the power domain information. Can this be used to apply the constraints on power domains, as proposed by [1]?

On-going developments, patches in preparation:
1. write Documentation for the new PM QoS class
2. validate the constraints framework on OMAP3&4
3. refine the power domains wake-up latency and the cpuidle figures

[1] http://marc.info/?l=linux-omap&m=130451613408148&w=2

Based on the master branch of the linux-omap git tree (3.0.0-rc3). Compile tested only using OMAP and x86 generic defconfigs.


Jean Pihet (8):
  PM: add a per-device wake-up latency constraints plist
  PM: extend PM QoS with per-device wake-up 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

Vishwanath BS (1):
  OMAP4: powerdomain data: add wake-up latency figures

 arch/arm/mach-omap2/cpuidle34xx.c            |   42 +---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 ++-
 arch/arm/mach-omap2/pm.h                     |   17 ++-
 arch/arm/mach-omap2/powerdomain.c            |  187 ++++++++++++++
 arch/arm/mach-omap2/powerdomain.h            |   33 +++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c  |   85 +++++++
 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     |  344 ++++++++++++++++++++++++++
 arch/arm/plat-omap/omap-pm-noop.c            |   89 -------
 drivers/base/power/main.c                    |    1 +
 drivers/i2c/busses/i2c-omap.c                |   35 ++-
 drivers/media/video/via-camera.c             |    5 +-
 drivers/net/e1000e/netdev.c                  |    9 +-
 drivers/net/wireless/ipw2x00/ipw2100.c       |    6 +-
 include/linux/pm.h                           |    2 +
 include/linux/pm_qos_params.h                |   40 ++--
 kernel/pm_qos_params.c                       |  142 ++++++-----
 sound/core/pcm_native.c                      |    8 +-
 23 files changed, 939 insertions(+), 367 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2011-06-30 15:08 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-24 14:37 [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
2011-06-24 14:37 ` [RFC/PATCH 1/9] PM: add a per-device wake-up latency constraints plist jean.pihet
2011-06-24 14:37 ` jean.pihet
2011-06-24 14:37 ` [RFC/PATCH 2/9] PM: extend PM QoS with per-device wake-up constraints jean.pihet
2011-06-24 14:37 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 3/9] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 4/9] OMAP2+: powerdomain: control power domains next state jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 5/9] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 6/9] OMAP4: " jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 7/9] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-24 14:38 ` [RFC/PATCH 8/9] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-27 18:33   ` Todd Poynor
2011-06-27 18:33   ` Todd Poynor
2011-06-30 15:08     ` Jean Pihet
2011-06-30 15:08     ` Jean Pihet
2011-06-24 14:38 ` [RFC/PATCH 9/9] OMAP2+: cpuidle only influences the MPU state jean.pihet
2011-06-24 14:38 ` jean.pihet
2011-06-25 13:23   ` Santosh Shilimkar
2011-06-27  6:53     ` Jean Pihet
2011-06-27 14:11       ` Santosh Shilimkar
2011-06-27 14:31         ` Jean Pihet
2011-06-27 14:31         ` Jean Pihet
2011-06-27 14:11       ` Santosh Shilimkar
2011-06-25 13:23   ` Santosh Shilimkar
2011-06-24 15:30 ` [RFC/PATCH 0/9] PM QoS: add a per-device wake-up latency constraint class jean.pihet
2011-06-24 15:30 ` jean.pihet
2011-06-27 13:40 ` [linux-pm] " mark gross
2011-06-30 15:07   ` Jean Pihet
2011-06-30 15:07   ` Jean Pihet
2011-06-27 13:40 ` mark gross
2011-06-24 14:37 jean.pihet

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.