All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
@ 2011-07-28  8:30 jean.pihet
  2011-07-28  8:30 ` [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos jean.pihet
                   ` (28 more replies)
  0 siblings, 29 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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.

High level implementation:

1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_LATENCY).
. Define a pm_qos_constraints struct for the storage of the constraints list
and associated values (target_value, default_value, type ...).
. Update the pm_qos_object struct with the information related to a PM QoS
class: ptr to constraints list, notifer ptr, name ...
. Each PM QoS class statically declare objects for pm_qos_object and
pm_qos_constraints. The only exception is the devices constraints, cf. below.
. The device constraints class is statically declaring a pm_qos_object. The
pm_qos_constraints are per-device and so are embedded into the device struct.

The new class is available from kernel drivers and shall be made available
to user space through a per-device sysfs entry. User space API to come as a 
subsequent patch.

2. Added a notification of device insertion/removal from the device PM framework
to PM QoS.
This allows to init/de-init the per-device constraints list upon device insertion
and removal.
RFC state for comments and review, lightly tested

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

4. Upon a change of the aggregated constraint value in the PM_QOS_DEV_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. 5 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.

5. 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_LATENCY class of the PM QoS framework, via the device
wake-up latency constraints callback to the OMAP_PM_CONSTRAINTS framework.

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 those figures.

6. Update the pm_qos_add_request callers to the generic API

7. Misc fixes to improve code readability:
. rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
. rename of fields names (request, list, constraints, class),
. simplification of the in-kernel PM QoS API implementation. The main logic part
is now implemented in the update_target function.

Questions:
1. per-device user-space API: since sysfs does not provide open/close
callbacks it is not possible to support multiple and simultaneous users of
the per-device sysfs entry. A user-space constraints aggregation application is
needed in case of multiple constraints for a device. Is this the way to go?

On-going developments, patches in preparation:
1. add a user-space API for the devices constratins PM QoS, using a sysfs entry
   per device
2. write Documentation for the new PM QoS class, once the RFC is agreed on
3. validate the constraints framework on OMAP4 HW (done on OMAP3)
4. 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-rc7). Compile
tested using OMAP and x86 generic defconfigs.
Lightly tested on OMAP3 Beagleboard (ES2.x).


Changelog:

v3:
. Complete PM QoS re-design after the comments on MLs
. Patch set split up for improved readability and easier maintenance

v2:
. Rework after comments on the mailing lists
. Added a notification of device insertion/removal from the device PM framework
. Validated on OMAP3 HW

v1:
. Initial implementation


Jean Pihet (12):
  PM: QoS: rename pm_qos_params files to pm_qos
  PM: add a per-device wake-up latency constraints plist
  PM: QoS: extend the in-kernel API with per-device latency constraints
  PM: QoS: implement the per-device latency constraints
  PM: QoS: support the dynamic insertion and removal of devices
  OMAP PM: create a PM layer plugin for per-device constraints
  OMAP PM: early init of the pwrdms states
  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-msm/clock.c                    |    2 +-
 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/pm34xx.c                 |    2 +-
 arch/arm/mach-omap2/pm44xx.c                 |    2 +-
 arch/arm/mach-omap2/powerdomain.c            |  190 +++++++++
 arch/arm/mach-omap2/powerdomain.h            |   33 ++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++
 arch/arm/mach-omap2/powerdomains44xx_data.c  |   84 ++++
 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/acpi/processor_idle.c                |    2 +-
 drivers/base/power/main.c                    |    4 +
 drivers/cpuidle/cpuidle.c                    |    2 +-
 drivers/cpuidle/governors/ladder.c           |    2 +-
 drivers/cpuidle/governors/menu.c             |    2 +-
 drivers/i2c/busses/i2c-omap.c                |   35 +-
 drivers/media/video/via-camera.c             |    9 +-
 drivers/net/e1000e/netdev.c                  |   11 +-
 drivers/net/wireless/ipw2x00/ipw2100.c       |   10 +-
 drivers/staging/msm/lcdc.c                   |    2 +-
 drivers/staging/msm/tvenc.c                  |    2 +-
 include/linux/netdevice.h                    |    4 +-
 include/linux/pm.h                           |    4 +
 include/linux/pm_qos.h                       |   68 ++++
 include/linux/pm_qos_params.h                |   38 --
 include/sound/pcm.h                          |    4 +-
 kernel/Makefile                              |    2 +-
 kernel/pm_qos.c                              |  557 ++++++++++++++++++++++++++
 kernel/pm_qos_params.c                       |  481 ----------------------
 net/mac80211/main.c                          |    2 +-
 net/mac80211/mlme.c                          |    2 +-
 net/mac80211/scan.c                          |    2 +-
 sound/core/pcm_native.c                      |   10 +-
 40 files changed, 1487 insertions(+), 834 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
 create mode 100644 include/linux/pm_qos.h
 delete mode 100644 include/linux/pm_qos_params.h
 create mode 100644 kernel/pm_qos.c
 delete mode 100644 kernel/pm_qos_params.c

-- 
1.7.2.5


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

* [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The PM QoS implementation files are better named
kernel/pm_qos.c and include/linux/pm_qos.h.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-msm/clock.c              |    2 +-
 drivers/acpi/processor_idle.c          |    2 +-
 drivers/cpuidle/cpuidle.c              |    2 +-
 drivers/cpuidle/governors/ladder.c     |    2 +-
 drivers/cpuidle/governors/menu.c       |    2 +-
 drivers/media/video/via-camera.c       |    2 +-
 drivers/net/e1000e/netdev.c            |    2 +-
 drivers/net/wireless/ipw2x00/ipw2100.c |    2 +-
 drivers/staging/msm/lcdc.c             |    2 +-
 drivers/staging/msm/tvenc.c            |    2 +-
 include/linux/netdevice.h              |    2 +-
 include/linux/pm_qos.h                 |   38 +++
 include/linux/pm_qos_params.h          |   38 ---
 include/sound/pcm.h                    |    2 +-
 kernel/Makefile                        |    2 +-
 kernel/pm_qos.c                        |  481 ++++++++++++++++++++++++++++++++
 kernel/pm_qos_params.c                 |  481 --------------------------------
 net/mac80211/main.c                    |    2 +-
 net/mac80211/mlme.c                    |    2 +-
 net/mac80211/scan.c                    |    2 +-
 sound/core/pcm_native.c                |    2 +-
 21 files changed, 536 insertions(+), 536 deletions(-)
 create mode 100644 include/linux/pm_qos.h
 delete mode 100644 include/linux/pm_qos_params.h
 create mode 100644 kernel/pm_qos.c
 delete mode 100644 kernel/pm_qos_params.c

diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 22a5376..d9145df 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -18,7 +18,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/string.h>
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 431ab11..2e69e09 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -37,7 +37,7 @@
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/sched.h>	/* need_resched() */
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/irqflags.h>
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index bf50924..eed4c47 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -12,7 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/ktime.h>
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 12c9890..f62fde2 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -14,7 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d0..3600f19 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/time.h>
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048..b3ca389 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -21,7 +21,7 @@
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
 #include <linux/via_i2c.h>
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 3310c3d..a8a18e1 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -46,7 +46,7 @@
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/aer.h>
 #include <linux/prefetch.h>
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 4430775..d9df575 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -161,7 +161,7 @@ that only one external action is invoked at a time.
 #include <linux/firmware.h>
 #include <linux/acpi.h>
 #include <linux/ctype.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include <net/lib80211.h>
 
diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c
index 8183394..1d5183d 100644
--- a/drivers/staging/msm/lcdc.c
+++ b/drivers/staging/msm/lcdc.c
@@ -32,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include "msm_fb.h"
 
diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c
index 4fbb77b..5a798b8 100644
--- a/drivers/staging/msm/tvenc.c
+++ b/drivers/staging/msm/tvenc.c
@@ -32,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #define TVENC_C
 #include "tvenc.h"
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 54b8b4d..cc1eb9e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -31,7 +31,7 @@
 #include <linux/if_link.h>
 
 #ifdef __KERNEL__
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
new file mode 100644
index 0000000..9cc0224
--- /dev/null
+++ b/include/linux/pm_qos.h
@@ -0,0 +1,38 @@
+#ifndef _LINUX_PM_QOS_H
+#define _LINUX_PM_QOS_H
+/* interface for the pm_qos_power infrastructure of the linux kernel.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+#include <linux/plist.h>
+#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_NUM_CLASSES 4
+#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
+
+struct pm_qos_request_list {
+	struct plist_node list;
+	int pm_qos_class;
+};
+
+void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
+void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
+		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_active(struct pm_qos_request_list *req);
+
+#endif
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
deleted file mode 100644
index a7d87f9..0000000
--- a/include/linux/pm_qos_params.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _LINUX_PM_QOS_PARAMS_H
-#define _LINUX_PM_QOS_PARAMS_H
-/* interface for the pm_qos_power infrastructure of the linux kernel.
- *
- * Mark Gross <mgross@linux.intel.com>
- */
-#include <linux/plist.h>
-#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_NUM_CLASSES 4
-#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
-
-struct pm_qos_request_list {
-	struct plist_node list;
-	int pm_qos_class;
-};
-
-void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		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_active(struct pm_qos_request_list *req);
-
-#endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index e1bad11..1204f17 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -29,7 +29,7 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #define snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_chip(pcm) ((pcm)->private_data)
diff --git a/kernel/Makefile b/kernel/Makefile
index 2d64cfc..3f6d0ed 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    rcupdate.o extable.o params.o posix-timers.o \
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
-	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
+	    notifier.o ksysfs.o pm_qos.o sched_clock.o cred.o \
 	    async.o range.o jump_label.o
 obj-y += groups.o
 
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
new file mode 100644
index 0000000..3bf69f1
--- /dev/null
+++ b/kernel/pm_qos.c
@@ -0,0 +1,481 @@
+/*
+ * This module exposes the interface to kernel space for specifying
+ * QoS dependencies.  It provides infrastructure for registration of:
+ *
+ * Dependents on a QoS value : register requests
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based.  Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ *
+ * There are 3 basic classes of QoS parameter: latency, timeout, throughput
+ * each have defined units:
+ * latency: usec
+ * timeout: usec <-- currently not used.
+ * throughput: kbs (kilo byte / sec)
+ *
+ * There are lists of pm_qos_objects each one wrapping requests, notifiers
+ *
+ * User mode requests on a QOS parameter register themselves to the
+ * subsystem by opening the device node /dev/... and writing there request to
+ * the node.  As long as the process holds a file handle open to the node the
+ * client continues to be accounted for.  Upon file release the usermode
+ * request is removed and a new qos target is computed.  This way when the
+ * request that the application has is cleaned up when closes the file
+ * pointer or exits the pm_qos_object will get an opportunity to clean up.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+
+/*#define DEBUG*/
+
+#include <linux/pm_qos.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * locking rule: all changes to requests or notifiers lists
+ * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
+ * held, taken with _irqsave.  One lock to rule them all
+ */
+enum pm_qos_type {
+	PM_QOS_MAX,		/* return the largest value */
+	PM_QOS_MIN		/* return the smallest value */
+};
+
+/*
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically.  Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
+struct pm_qos_object {
+	struct plist_head requests;
+	struct blocking_notifier_head *notifiers;
+	struct miscdevice pm_qos_power_miscdev;
+	char *name;
+	s32 target_value;	/* Do not change to 64 bit */
+	s32 default_value;
+	enum pm_qos_type type;
+};
+
+static DEFINE_SPINLOCK(pm_qos_lock);
+
+static struct pm_qos_object null_pm_qos;
+static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
+static struct pm_qos_object cpu_dma_pm_qos = {
+	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
+	.notifiers = &cpu_dma_lat_notifier,
+	.name = "cpu_dma_latency",
+	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_CPU_DMA_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),
+	.notifiers = &network_lat_notifier,
+	.name = "network_latency",
+	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
+static struct pm_qos_object network_throughput_pm_qos = {
+	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
+	.notifiers = &network_throughput_notifier,
+	.name = "network_throughput",
+	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.type = PM_QOS_MAX,
+};
+
+
+static struct pm_qos_object *pm_qos_array[] = {
+	&null_pm_qos,
+	&cpu_dma_pm_qos,
+	&network_lat_pm_qos,
+	&network_throughput_pm_qos
+};
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos);
+static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *f_pos);
+static int pm_qos_power_open(struct inode *inode, struct file *filp);
+static int pm_qos_power_release(struct inode *inode, struct file *filp);
+
+static const struct file_operations pm_qos_power_fops = {
+	.write = pm_qos_power_write,
+	.read = pm_qos_power_read,
+	.open = pm_qos_power_open,
+	.release = pm_qos_power_release,
+	.llseek = noop_llseek,
+};
+
+/* unlocked internal variant */
+static inline int pm_qos_get_value(struct pm_qos_object *o)
+{
+	if (plist_head_empty(&o->requests))
+		return o->default_value;
+
+	switch (o->type) {
+	case PM_QOS_MIN:
+		return plist_first(&o->requests)->prio;
+
+	case PM_QOS_MAX:
+		return plist_last(&o->requests)->prio;
+
+	default:
+		/* runtime check for not using enum */
+		BUG();
+	}
+}
+
+static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+{
+	return o->target_value;
+}
+
+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)
+{
+	unsigned long flags;
+	int prev_value, curr_value;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	prev_value = pm_qos_get_value(o);
+	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
+	if (value != PM_QOS_DEFAULT_VALUE) {
+		/*
+		 * to change the list, we atomically remove, reinit
+		 * with new value and add, then see if the extremal
+		 * changed
+		 */
+		plist_del(node, &o->requests);
+		plist_node_init(node, value);
+		plist_add(node, &o->requests);
+	} else if (del) {
+		plist_del(node, &o->requests);
+	} else {
+		plist_add(node, &o->requests);
+	}
+	curr_value = pm_qos_get_value(o);
+	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);
+}
+
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+	qos->pm_qos_power_miscdev.name = qos->name;
+	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+	return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+	int pm_qos_class;
+
+	for (pm_qos_class = 0;
+		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+		if (minor ==
+			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+			return pm_qos_class;
+	}
+	return -1;
+}
+
+/**
+ * pm_qos_request - returns current system wide qos expectation
+ * @pm_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value.
+ */
+int pm_qos_request(int pm_qos_class)
+{
+	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
+}
+EXPORT_SYMBOL_GPL(pm_qos_request);
+
+int pm_qos_request_active(struct pm_qos_request_list *req)
+{
+	return req->pm_qos_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
+ *
+ * This function inserts a new entry in the pm_qos_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
+ * removal.
+ */
+
+void pm_qos_add_request(struct pm_qos_request_list *dep,
+			int pm_qos_class, s32 value)
+{
+	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	int new_value;
+
+	if (pm_qos_request_active(dep)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+		return;
+	}
+	if (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);
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_request);
+
+/**
+ * pm_qos_update_request - modifies an existing qos 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.
+ *
+ * Attempts are made to make this code callable on hot code paths.
+ */
+void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
+			   s32 new_value)
+{
+	s32 temp;
+	struct pm_qos_object *o;
+
+	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");
+		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);
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_request);
+
+/**
+ * pm_qos_remove_request - modifies an existing qos 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
+ * 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");
+		return;
+	}
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	update_target(o, &pm_qos_req->list, 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.
+ * @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.
+ */
+int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+	int retval;
+
+	retval = blocking_notifier_chain_register(
+			pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+	return retval;
+}
+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.
+ * @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.
+ */
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+	int retval;
+
+	retval = blocking_notifier_chain_unregister(
+			pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+
+static int pm_qos_power_open(struct inode *inode, struct file *filp)
+{
+	long pm_qos_class;
+
+	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);
+		if (!req)
+			return -ENOMEM;
+
+		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+		filp->private_data = req;
+
+		if (filp->private_data)
+			return 0;
+	}
+	return -EPERM;
+}
+
+static int pm_qos_power_release(struct inode *inode, struct file *filp)
+{
+	struct pm_qos_request_list *req;
+
+	req = filp->private_data;
+	pm_qos_remove_request(req);
+	kfree(req);
+
+	return 0;
+}
+
+
+static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	s32 value;
+	unsigned long flags;
+	struct pm_qos_object *o;
+	struct pm_qos_request_list *pm_qos_req = filp->private_data;
+
+	if (!pm_qos_req)
+		return -EINVAL;
+	if (!pm_qos_request_active(pm_qos_req))
+		return -EINVAL;
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	value = pm_qos_get_value(o);
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
+}
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	s32 value;
+	struct pm_qos_request_list *pm_qos_req;
+
+	if (count == sizeof(s32)) {
+		if (copy_from_user(&value, buf, sizeof(s32)))
+			return -EFAULT;
+	} else if (count <= 11) { /* ASCII perhaps? */
+		char ascii_value[11];
+		unsigned long int ulval;
+		int ret;
+
+		if (copy_from_user(ascii_value, buf, count))
+			return -EFAULT;
+
+		if (count > 10) {
+			if (ascii_value[10] == '\n')
+				ascii_value[10] = '\0';
+			else
+				return -EINVAL;
+		} else {
+			ascii_value[count] = '\0';
+		}
+		ret = strict_strtoul(ascii_value, 16, &ulval);
+		if (ret) {
+			pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
+			return -EINVAL;
+		}
+		value = (s32)lower_32_bits(ulval);
+	} else {
+		return -EINVAL;
+	}
+
+	pm_qos_req = filp->private_data;
+	pm_qos_update_request(pm_qos_req, value);
+
+	return count;
+}
+
+
+static int __init pm_qos_power_init(void)
+{
+	int ret = 0;
+
+	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
+	if (ret < 0) {
+		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");
+		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");
+
+	return ret;
+}
+
+late_initcall(pm_qos_power_init);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
deleted file mode 100644
index 6824ca7..0000000
--- a/kernel/pm_qos_params.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * This module exposes the interface to kernel space for specifying
- * QoS dependencies.  It provides infrastructure for registration of:
- *
- * Dependents on a QoS value : register requests
- * Watchers of QoS value : get notified when target QoS value changes
- *
- * This QoS design is best effort based.  Dependents register their QoS needs.
- * Watchers register to keep track of the current QoS needs of the system.
- *
- * There are 3 basic classes of QoS parameter: latency, timeout, throughput
- * each have defined units:
- * latency: usec
- * timeout: usec <-- currently not used.
- * throughput: kbs (kilo byte / sec)
- *
- * There are lists of pm_qos_objects each one wrapping requests, notifiers
- *
- * User mode requests on a QOS parameter register themselves to the
- * subsystem by opening the device node /dev/... and writing there request to
- * the node.  As long as the process holds a file handle open to the node the
- * client continues to be accounted for.  Upon file release the usermode
- * request is removed and a new qos target is computed.  This way when the
- * request that the application has is cleaned up when closes the file
- * pointer or exits the pm_qos_object will get an opportunity to clean up.
- *
- * Mark Gross <mgross@linux.intel.com>
- */
-
-/*#define DEBUG*/
-
-#include <linux/pm_qos_params.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/uaccess.h>
-
-/*
- * locking rule: all changes to requests or notifiers lists
- * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
- * held, taken with _irqsave.  One lock to rule them all
- */
-enum pm_qos_type {
-	PM_QOS_MAX,		/* return the largest value */
-	PM_QOS_MIN		/* return the smallest value */
-};
-
-/*
- * Note: The lockless read path depends on the CPU accessing
- * target_value atomically.  Atomic access is only guaranteed on all CPU
- * types linux supports for 32 bit quantites
- */
-struct pm_qos_object {
-	struct plist_head requests;
-	struct blocking_notifier_head *notifiers;
-	struct miscdevice pm_qos_power_miscdev;
-	char *name;
-	s32 target_value;	/* Do not change to 64 bit */
-	s32 default_value;
-	enum pm_qos_type type;
-};
-
-static DEFINE_SPINLOCK(pm_qos_lock);
-
-static struct pm_qos_object null_pm_qos;
-static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
-static struct pm_qos_object cpu_dma_pm_qos = {
-	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
-	.notifiers = &cpu_dma_lat_notifier,
-	.name = "cpu_dma_latency",
-	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_CPU_DMA_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),
-	.notifiers = &network_lat_notifier,
-	.name = "network_latency",
-	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN
-};
-
-
-static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
-static struct pm_qos_object network_throughput_pm_qos = {
-	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
-	.notifiers = &network_throughput_notifier,
-	.name = "network_throughput",
-	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.type = PM_QOS_MAX,
-};
-
-
-static struct pm_qos_object *pm_qos_array[] = {
-	&null_pm_qos,
-	&cpu_dma_pm_qos,
-	&network_lat_pm_qos,
-	&network_throughput_pm_qos
-};
-
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-		size_t count, loff_t *f_pos);
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-		size_t count, loff_t *f_pos);
-static int pm_qos_power_open(struct inode *inode, struct file *filp);
-static int pm_qos_power_release(struct inode *inode, struct file *filp);
-
-static const struct file_operations pm_qos_power_fops = {
-	.write = pm_qos_power_write,
-	.read = pm_qos_power_read,
-	.open = pm_qos_power_open,
-	.release = pm_qos_power_release,
-	.llseek = noop_llseek,
-};
-
-/* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_object *o)
-{
-	if (plist_head_empty(&o->requests))
-		return o->default_value;
-
-	switch (o->type) {
-	case PM_QOS_MIN:
-		return plist_first(&o->requests)->prio;
-
-	case PM_QOS_MAX:
-		return plist_last(&o->requests)->prio;
-
-	default:
-		/* runtime check for not using enum */
-		BUG();
-	}
-}
-
-static inline s32 pm_qos_read_value(struct pm_qos_object *o)
-{
-	return o->target_value;
-}
-
-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)
-{
-	unsigned long flags;
-	int prev_value, curr_value;
-
-	spin_lock_irqsave(&pm_qos_lock, flags);
-	prev_value = pm_qos_get_value(o);
-	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
-	if (value != PM_QOS_DEFAULT_VALUE) {
-		/*
-		 * to change the list, we atomically remove, reinit
-		 * with new value and add, then see if the extremal
-		 * changed
-		 */
-		plist_del(node, &o->requests);
-		plist_node_init(node, value);
-		plist_add(node, &o->requests);
-	} else if (del) {
-		plist_del(node, &o->requests);
-	} else {
-		plist_add(node, &o->requests);
-	}
-	curr_value = pm_qos_get_value(o);
-	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);
-}
-
-static int register_pm_qos_misc(struct pm_qos_object *qos)
-{
-	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-	qos->pm_qos_power_miscdev.name = qos->name;
-	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
-	return misc_register(&qos->pm_qos_power_miscdev);
-}
-
-static int find_pm_qos_object_by_minor(int minor)
-{
-	int pm_qos_class;
-
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
-		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
-	}
-	return -1;
-}
-
-/**
- * pm_qos_request - returns current system wide qos expectation
- * @pm_qos_class: identification of which qos value is requested
- *
- * This function returns the current target value.
- */
-int pm_qos_request(int pm_qos_class)
-{
-	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
-}
-EXPORT_SYMBOL_GPL(pm_qos_request);
-
-int pm_qos_request_active(struct pm_qos_request_list *req)
-{
-	return req->pm_qos_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
- *
- * This function inserts a new entry in the pm_qos_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
- * removal.
- */
-
-void pm_qos_add_request(struct pm_qos_request_list *dep,
-			int pm_qos_class, s32 value)
-{
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
-	int new_value;
-
-	if (pm_qos_request_active(dep)) {
-		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
-		return;
-	}
-	if (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);
-}
-EXPORT_SYMBOL_GPL(pm_qos_add_request);
-
-/**
- * pm_qos_update_request - modifies an existing qos 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.
- *
- * Attempts are made to make this code callable on hot code paths.
- */
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-			   s32 new_value)
-{
-	s32 temp;
-	struct pm_qos_object *o;
-
-	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");
-		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);
-}
-EXPORT_SYMBOL_GPL(pm_qos_update_request);
-
-/**
- * pm_qos_remove_request - modifies an existing qos 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
- * 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");
-		return;
-	}
-
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	update_target(o, &pm_qos_req->list, 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.
- * @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.
- */
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-	int retval;
-
-	retval = blocking_notifier_chain_register(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
-
-	return retval;
-}
-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.
- * @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.
- */
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-	int retval;
-
-	retval = blocking_notifier_chain_unregister(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
-
-static int pm_qos_power_open(struct inode *inode, struct file *filp)
-{
-	long pm_qos_class;
-
-	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);
-		if (!req)
-			return -ENOMEM;
-
-		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
-		filp->private_data = req;
-
-		if (filp->private_data)
-			return 0;
-	}
-	return -EPERM;
-}
-
-static int pm_qos_power_release(struct inode *inode, struct file *filp)
-{
-	struct pm_qos_request_list *req;
-
-	req = filp->private_data;
-	pm_qos_remove_request(req);
-	kfree(req);
-
-	return 0;
-}
-
-
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-		size_t count, loff_t *f_pos)
-{
-	s32 value;
-	unsigned long flags;
-	struct pm_qos_object *o;
-	struct pm_qos_request_list *pm_qos_req = filp->private_data;
-
-	if (!pm_qos_req)
-		return -EINVAL;
-	if (!pm_qos_request_active(pm_qos_req))
-		return -EINVAL;
-
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	spin_lock_irqsave(&pm_qos_lock, flags);
-	value = pm_qos_get_value(o);
-	spin_unlock_irqrestore(&pm_qos_lock, flags);
-
-	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
-}
-
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-		size_t count, loff_t *f_pos)
-{
-	s32 value;
-	struct pm_qos_request_list *pm_qos_req;
-
-	if (count == sizeof(s32)) {
-		if (copy_from_user(&value, buf, sizeof(s32)))
-			return -EFAULT;
-	} else if (count <= 11) { /* ASCII perhaps? */
-		char ascii_value[11];
-		unsigned long int ulval;
-		int ret;
-
-		if (copy_from_user(ascii_value, buf, count))
-			return -EFAULT;
-
-		if (count > 10) {
-			if (ascii_value[10] == '\n')
-				ascii_value[10] = '\0';
-			else
-				return -EINVAL;
-		} else {
-			ascii_value[count] = '\0';
-		}
-		ret = strict_strtoul(ascii_value, 16, &ulval);
-		if (ret) {
-			pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
-			return -EINVAL;
-		}
-		value = (s32)lower_32_bits(ulval);
-	} else {
-		return -EINVAL;
-	}
-
-	pm_qos_req = filp->private_data;
-	pm_qos_update_request(pm_qos_req, value);
-
-	return count;
-}
-
-
-static int __init pm_qos_power_init(void)
-{
-	int ret = 0;
-
-	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
-	if (ret < 0) {
-		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");
-		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");
-
-	return ret;
-}
-
-late_initcall(pm_qos_power_init);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 866f269..bb771e9 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -19,7 +19,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/inetdevice.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d595265..f07705d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -17,7 +17,7 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/crc32.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 58ffa7d..41393c4 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -14,7 +14,7 @@
 
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <net/sch_generic.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 1c6be91..c74e228 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,7 +23,7 @@
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
 #include <sound/core.h>
-- 
1.7.2.5

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

* [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
  2011-07-28  8:30 ` [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-29 21:57   ` Rafael J. Wysocki
  2011-07-28  8:30 ` [PATCH 02/13] PM: add a per-device wake-up latency constraints plist jean.pihet
                   ` (26 subsequent siblings)
  28 siblings, 1 reply; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The PM QoS implementation files are better named
kernel/pm_qos.c and include/linux/pm_qos.h.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-msm/clock.c              |    2 +-
 drivers/acpi/processor_idle.c          |    2 +-
 drivers/cpuidle/cpuidle.c              |    2 +-
 drivers/cpuidle/governors/ladder.c     |    2 +-
 drivers/cpuidle/governors/menu.c       |    2 +-
 drivers/media/video/via-camera.c       |    2 +-
 drivers/net/e1000e/netdev.c            |    2 +-
 drivers/net/wireless/ipw2x00/ipw2100.c |    2 +-
 drivers/staging/msm/lcdc.c             |    2 +-
 drivers/staging/msm/tvenc.c            |    2 +-
 include/linux/netdevice.h              |    2 +-
 include/linux/pm_qos.h                 |   38 +++
 include/linux/pm_qos_params.h          |   38 ---
 include/sound/pcm.h                    |    2 +-
 kernel/Makefile                        |    2 +-
 kernel/pm_qos.c                        |  481 ++++++++++++++++++++++++++++++++
 kernel/pm_qos_params.c                 |  481 --------------------------------
 net/mac80211/main.c                    |    2 +-
 net/mac80211/mlme.c                    |    2 +-
 net/mac80211/scan.c                    |    2 +-
 sound/core/pcm_native.c                |    2 +-
 21 files changed, 536 insertions(+), 536 deletions(-)
 create mode 100644 include/linux/pm_qos.h
 delete mode 100644 include/linux/pm_qos_params.h
 create mode 100644 kernel/pm_qos.c
 delete mode 100644 kernel/pm_qos_params.c

diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 22a5376..d9145df 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -18,7 +18,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/string.h>
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 431ab11..2e69e09 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -37,7 +37,7 @@
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/sched.h>	/* need_resched() */
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/irqflags.h>
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index bf50924..eed4c47 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -12,7 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/ktime.h>
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 12c9890..f62fde2 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -14,7 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d0..3600f19 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/time.h>
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048..b3ca389 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -21,7 +21,7 @@
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
 #include <linux/via_i2c.h>
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 3310c3d..a8a18e1 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -46,7 +46,7 @@
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/aer.h>
 #include <linux/prefetch.h>
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 4430775..d9df575 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -161,7 +161,7 @@ that only one external action is invoked at a time.
 #include <linux/firmware.h>
 #include <linux/acpi.h>
 #include <linux/ctype.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include <net/lib80211.h>
 
diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c
index 8183394..1d5183d 100644
--- a/drivers/staging/msm/lcdc.c
+++ b/drivers/staging/msm/lcdc.c
@@ -32,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include "msm_fb.h"
 
diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c
index 4fbb77b..5a798b8 100644
--- a/drivers/staging/msm/tvenc.c
+++ b/drivers/staging/msm/tvenc.c
@@ -32,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #define TVENC_C
 #include "tvenc.h"
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 54b8b4d..cc1eb9e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -31,7 +31,7 @@
 #include <linux/if_link.h>
 
 #ifdef __KERNEL__
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
new file mode 100644
index 0000000..9cc0224
--- /dev/null
+++ b/include/linux/pm_qos.h
@@ -0,0 +1,38 @@
+#ifndef _LINUX_PM_QOS_H
+#define _LINUX_PM_QOS_H
+/* interface for the pm_qos_power infrastructure of the linux kernel.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+#include <linux/plist.h>
+#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_NUM_CLASSES 4
+#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
+
+struct pm_qos_request_list {
+	struct plist_node list;
+	int pm_qos_class;
+};
+
+void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
+void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
+		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_active(struct pm_qos_request_list *req);
+
+#endif
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
deleted file mode 100644
index a7d87f9..0000000
--- a/include/linux/pm_qos_params.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _LINUX_PM_QOS_PARAMS_H
-#define _LINUX_PM_QOS_PARAMS_H
-/* interface for the pm_qos_power infrastructure of the linux kernel.
- *
- * Mark Gross <mgross@linux.intel.com>
- */
-#include <linux/plist.h>
-#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_NUM_CLASSES 4
-#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
-
-struct pm_qos_request_list {
-	struct plist_node list;
-	int pm_qos_class;
-};
-
-void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		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_active(struct pm_qos_request_list *req);
-
-#endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index e1bad11..1204f17 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -29,7 +29,7 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #define snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_chip(pcm) ((pcm)->private_data)
diff --git a/kernel/Makefile b/kernel/Makefile
index 2d64cfc..3f6d0ed 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    rcupdate.o extable.o params.o posix-timers.o \
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
-	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
+	    notifier.o ksysfs.o pm_qos.o sched_clock.o cred.o \
 	    async.o range.o jump_label.o
 obj-y += groups.o
 
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
new file mode 100644
index 0000000..3bf69f1
--- /dev/null
+++ b/kernel/pm_qos.c
@@ -0,0 +1,481 @@
+/*
+ * This module exposes the interface to kernel space for specifying
+ * QoS dependencies.  It provides infrastructure for registration of:
+ *
+ * Dependents on a QoS value : register requests
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based.  Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ *
+ * There are 3 basic classes of QoS parameter: latency, timeout, throughput
+ * each have defined units:
+ * latency: usec
+ * timeout: usec <-- currently not used.
+ * throughput: kbs (kilo byte / sec)
+ *
+ * There are lists of pm_qos_objects each one wrapping requests, notifiers
+ *
+ * User mode requests on a QOS parameter register themselves to the
+ * subsystem by opening the device node /dev/... and writing there request to
+ * the node.  As long as the process holds a file handle open to the node the
+ * client continues to be accounted for.  Upon file release the usermode
+ * request is removed and a new qos target is computed.  This way when the
+ * request that the application has is cleaned up when closes the file
+ * pointer or exits the pm_qos_object will get an opportunity to clean up.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+
+/*#define DEBUG*/
+
+#include <linux/pm_qos.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * locking rule: all changes to requests or notifiers lists
+ * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
+ * held, taken with _irqsave.  One lock to rule them all
+ */
+enum pm_qos_type {
+	PM_QOS_MAX,		/* return the largest value */
+	PM_QOS_MIN		/* return the smallest value */
+};
+
+/*
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically.  Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
+struct pm_qos_object {
+	struct plist_head requests;
+	struct blocking_notifier_head *notifiers;
+	struct miscdevice pm_qos_power_miscdev;
+	char *name;
+	s32 target_value;	/* Do not change to 64 bit */
+	s32 default_value;
+	enum pm_qos_type type;
+};
+
+static DEFINE_SPINLOCK(pm_qos_lock);
+
+static struct pm_qos_object null_pm_qos;
+static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
+static struct pm_qos_object cpu_dma_pm_qos = {
+	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
+	.notifiers = &cpu_dma_lat_notifier,
+	.name = "cpu_dma_latency",
+	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_CPU_DMA_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),
+	.notifiers = &network_lat_notifier,
+	.name = "network_latency",
+	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
+static struct pm_qos_object network_throughput_pm_qos = {
+	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
+	.notifiers = &network_throughput_notifier,
+	.name = "network_throughput",
+	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.type = PM_QOS_MAX,
+};
+
+
+static struct pm_qos_object *pm_qos_array[] = {
+	&null_pm_qos,
+	&cpu_dma_pm_qos,
+	&network_lat_pm_qos,
+	&network_throughput_pm_qos
+};
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos);
+static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *f_pos);
+static int pm_qos_power_open(struct inode *inode, struct file *filp);
+static int pm_qos_power_release(struct inode *inode, struct file *filp);
+
+static const struct file_operations pm_qos_power_fops = {
+	.write = pm_qos_power_write,
+	.read = pm_qos_power_read,
+	.open = pm_qos_power_open,
+	.release = pm_qos_power_release,
+	.llseek = noop_llseek,
+};
+
+/* unlocked internal variant */
+static inline int pm_qos_get_value(struct pm_qos_object *o)
+{
+	if (plist_head_empty(&o->requests))
+		return o->default_value;
+
+	switch (o->type) {
+	case PM_QOS_MIN:
+		return plist_first(&o->requests)->prio;
+
+	case PM_QOS_MAX:
+		return plist_last(&o->requests)->prio;
+
+	default:
+		/* runtime check for not using enum */
+		BUG();
+	}
+}
+
+static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+{
+	return o->target_value;
+}
+
+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)
+{
+	unsigned long flags;
+	int prev_value, curr_value;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	prev_value = pm_qos_get_value(o);
+	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
+	if (value != PM_QOS_DEFAULT_VALUE) {
+		/*
+		 * to change the list, we atomically remove, reinit
+		 * with new value and add, then see if the extremal
+		 * changed
+		 */
+		plist_del(node, &o->requests);
+		plist_node_init(node, value);
+		plist_add(node, &o->requests);
+	} else if (del) {
+		plist_del(node, &o->requests);
+	} else {
+		plist_add(node, &o->requests);
+	}
+	curr_value = pm_qos_get_value(o);
+	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);
+}
+
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+	qos->pm_qos_power_miscdev.name = qos->name;
+	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+	return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+	int pm_qos_class;
+
+	for (pm_qos_class = 0;
+		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+		if (minor ==
+			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+			return pm_qos_class;
+	}
+	return -1;
+}
+
+/**
+ * pm_qos_request - returns current system wide qos expectation
+ * @pm_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value.
+ */
+int pm_qos_request(int pm_qos_class)
+{
+	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
+}
+EXPORT_SYMBOL_GPL(pm_qos_request);
+
+int pm_qos_request_active(struct pm_qos_request_list *req)
+{
+	return req->pm_qos_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
+ *
+ * This function inserts a new entry in the pm_qos_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
+ * removal.
+ */
+
+void pm_qos_add_request(struct pm_qos_request_list *dep,
+			int pm_qos_class, s32 value)
+{
+	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	int new_value;
+
+	if (pm_qos_request_active(dep)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+		return;
+	}
+	if (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);
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_request);
+
+/**
+ * pm_qos_update_request - modifies an existing qos 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.
+ *
+ * Attempts are made to make this code callable on hot code paths.
+ */
+void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
+			   s32 new_value)
+{
+	s32 temp;
+	struct pm_qos_object *o;
+
+	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");
+		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);
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_request);
+
+/**
+ * pm_qos_remove_request - modifies an existing qos 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
+ * 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");
+		return;
+	}
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	update_target(o, &pm_qos_req->list, 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.
+ * @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.
+ */
+int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+	int retval;
+
+	retval = blocking_notifier_chain_register(
+			pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+	return retval;
+}
+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.
+ * @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.
+ */
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+	int retval;
+
+	retval = blocking_notifier_chain_unregister(
+			pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+
+static int pm_qos_power_open(struct inode *inode, struct file *filp)
+{
+	long pm_qos_class;
+
+	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);
+		if (!req)
+			return -ENOMEM;
+
+		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+		filp->private_data = req;
+
+		if (filp->private_data)
+			return 0;
+	}
+	return -EPERM;
+}
+
+static int pm_qos_power_release(struct inode *inode, struct file *filp)
+{
+	struct pm_qos_request_list *req;
+
+	req = filp->private_data;
+	pm_qos_remove_request(req);
+	kfree(req);
+
+	return 0;
+}
+
+
+static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	s32 value;
+	unsigned long flags;
+	struct pm_qos_object *o;
+	struct pm_qos_request_list *pm_qos_req = filp->private_data;
+
+	if (!pm_qos_req)
+		return -EINVAL;
+	if (!pm_qos_request_active(pm_qos_req))
+		return -EINVAL;
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	value = pm_qos_get_value(o);
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
+}
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	s32 value;
+	struct pm_qos_request_list *pm_qos_req;
+
+	if (count == sizeof(s32)) {
+		if (copy_from_user(&value, buf, sizeof(s32)))
+			return -EFAULT;
+	} else if (count <= 11) { /* ASCII perhaps? */
+		char ascii_value[11];
+		unsigned long int ulval;
+		int ret;
+
+		if (copy_from_user(ascii_value, buf, count))
+			return -EFAULT;
+
+		if (count > 10) {
+			if (ascii_value[10] == '\n')
+				ascii_value[10] = '\0';
+			else
+				return -EINVAL;
+		} else {
+			ascii_value[count] = '\0';
+		}
+		ret = strict_strtoul(ascii_value, 16, &ulval);
+		if (ret) {
+			pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
+			return -EINVAL;
+		}
+		value = (s32)lower_32_bits(ulval);
+	} else {
+		return -EINVAL;
+	}
+
+	pm_qos_req = filp->private_data;
+	pm_qos_update_request(pm_qos_req, value);
+
+	return count;
+}
+
+
+static int __init pm_qos_power_init(void)
+{
+	int ret = 0;
+
+	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
+	if (ret < 0) {
+		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");
+		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");
+
+	return ret;
+}
+
+late_initcall(pm_qos_power_init);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
deleted file mode 100644
index 6824ca7..0000000
--- a/kernel/pm_qos_params.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * This module exposes the interface to kernel space for specifying
- * QoS dependencies.  It provides infrastructure for registration of:
- *
- * Dependents on a QoS value : register requests
- * Watchers of QoS value : get notified when target QoS value changes
- *
- * This QoS design is best effort based.  Dependents register their QoS needs.
- * Watchers register to keep track of the current QoS needs of the system.
- *
- * There are 3 basic classes of QoS parameter: latency, timeout, throughput
- * each have defined units:
- * latency: usec
- * timeout: usec <-- currently not used.
- * throughput: kbs (kilo byte / sec)
- *
- * There are lists of pm_qos_objects each one wrapping requests, notifiers
- *
- * User mode requests on a QOS parameter register themselves to the
- * subsystem by opening the device node /dev/... and writing there request to
- * the node.  As long as the process holds a file handle open to the node the
- * client continues to be accounted for.  Upon file release the usermode
- * request is removed and a new qos target is computed.  This way when the
- * request that the application has is cleaned up when closes the file
- * pointer or exits the pm_qos_object will get an opportunity to clean up.
- *
- * Mark Gross <mgross@linux.intel.com>
- */
-
-/*#define DEBUG*/
-
-#include <linux/pm_qos_params.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/uaccess.h>
-
-/*
- * locking rule: all changes to requests or notifiers lists
- * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
- * held, taken with _irqsave.  One lock to rule them all
- */
-enum pm_qos_type {
-	PM_QOS_MAX,		/* return the largest value */
-	PM_QOS_MIN		/* return the smallest value */
-};
-
-/*
- * Note: The lockless read path depends on the CPU accessing
- * target_value atomically.  Atomic access is only guaranteed on all CPU
- * types linux supports for 32 bit quantites
- */
-struct pm_qos_object {
-	struct plist_head requests;
-	struct blocking_notifier_head *notifiers;
-	struct miscdevice pm_qos_power_miscdev;
-	char *name;
-	s32 target_value;	/* Do not change to 64 bit */
-	s32 default_value;
-	enum pm_qos_type type;
-};
-
-static DEFINE_SPINLOCK(pm_qos_lock);
-
-static struct pm_qos_object null_pm_qos;
-static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
-static struct pm_qos_object cpu_dma_pm_qos = {
-	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
-	.notifiers = &cpu_dma_lat_notifier,
-	.name = "cpu_dma_latency",
-	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_CPU_DMA_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),
-	.notifiers = &network_lat_notifier,
-	.name = "network_latency",
-	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN
-};
-
-
-static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
-static struct pm_qos_object network_throughput_pm_qos = {
-	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
-	.notifiers = &network_throughput_notifier,
-	.name = "network_throughput",
-	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.type = PM_QOS_MAX,
-};
-
-
-static struct pm_qos_object *pm_qos_array[] = {
-	&null_pm_qos,
-	&cpu_dma_pm_qos,
-	&network_lat_pm_qos,
-	&network_throughput_pm_qos
-};
-
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-		size_t count, loff_t *f_pos);
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-		size_t count, loff_t *f_pos);
-static int pm_qos_power_open(struct inode *inode, struct file *filp);
-static int pm_qos_power_release(struct inode *inode, struct file *filp);
-
-static const struct file_operations pm_qos_power_fops = {
-	.write = pm_qos_power_write,
-	.read = pm_qos_power_read,
-	.open = pm_qos_power_open,
-	.release = pm_qos_power_release,
-	.llseek = noop_llseek,
-};
-
-/* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_object *o)
-{
-	if (plist_head_empty(&o->requests))
-		return o->default_value;
-
-	switch (o->type) {
-	case PM_QOS_MIN:
-		return plist_first(&o->requests)->prio;
-
-	case PM_QOS_MAX:
-		return plist_last(&o->requests)->prio;
-
-	default:
-		/* runtime check for not using enum */
-		BUG();
-	}
-}
-
-static inline s32 pm_qos_read_value(struct pm_qos_object *o)
-{
-	return o->target_value;
-}
-
-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)
-{
-	unsigned long flags;
-	int prev_value, curr_value;
-
-	spin_lock_irqsave(&pm_qos_lock, flags);
-	prev_value = pm_qos_get_value(o);
-	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
-	if (value != PM_QOS_DEFAULT_VALUE) {
-		/*
-		 * to change the list, we atomically remove, reinit
-		 * with new value and add, then see if the extremal
-		 * changed
-		 */
-		plist_del(node, &o->requests);
-		plist_node_init(node, value);
-		plist_add(node, &o->requests);
-	} else if (del) {
-		plist_del(node, &o->requests);
-	} else {
-		plist_add(node, &o->requests);
-	}
-	curr_value = pm_qos_get_value(o);
-	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);
-}
-
-static int register_pm_qos_misc(struct pm_qos_object *qos)
-{
-	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-	qos->pm_qos_power_miscdev.name = qos->name;
-	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
-	return misc_register(&qos->pm_qos_power_miscdev);
-}
-
-static int find_pm_qos_object_by_minor(int minor)
-{
-	int pm_qos_class;
-
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
-		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
-	}
-	return -1;
-}
-
-/**
- * pm_qos_request - returns current system wide qos expectation
- * @pm_qos_class: identification of which qos value is requested
- *
- * This function returns the current target value.
- */
-int pm_qos_request(int pm_qos_class)
-{
-	return pm_qos_read_value(pm_qos_array[pm_qos_class]);
-}
-EXPORT_SYMBOL_GPL(pm_qos_request);
-
-int pm_qos_request_active(struct pm_qos_request_list *req)
-{
-	return req->pm_qos_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
- *
- * This function inserts a new entry in the pm_qos_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
- * removal.
- */
-
-void pm_qos_add_request(struct pm_qos_request_list *dep,
-			int pm_qos_class, s32 value)
-{
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
-	int new_value;
-
-	if (pm_qos_request_active(dep)) {
-		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
-		return;
-	}
-	if (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);
-}
-EXPORT_SYMBOL_GPL(pm_qos_add_request);
-
-/**
- * pm_qos_update_request - modifies an existing qos 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.
- *
- * Attempts are made to make this code callable on hot code paths.
- */
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-			   s32 new_value)
-{
-	s32 temp;
-	struct pm_qos_object *o;
-
-	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");
-		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);
-}
-EXPORT_SYMBOL_GPL(pm_qos_update_request);
-
-/**
- * pm_qos_remove_request - modifies an existing qos 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
- * 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");
-		return;
-	}
-
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	update_target(o, &pm_qos_req->list, 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.
- * @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.
- */
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-	int retval;
-
-	retval = blocking_notifier_chain_register(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
-
-	return retval;
-}
-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.
- * @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.
- */
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-	int retval;
-
-	retval = blocking_notifier_chain_unregister(
-			pm_qos_array[pm_qos_class]->notifiers, notifier);
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
-
-static int pm_qos_power_open(struct inode *inode, struct file *filp)
-{
-	long pm_qos_class;
-
-	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);
-		if (!req)
-			return -ENOMEM;
-
-		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
-		filp->private_data = req;
-
-		if (filp->private_data)
-			return 0;
-	}
-	return -EPERM;
-}
-
-static int pm_qos_power_release(struct inode *inode, struct file *filp)
-{
-	struct pm_qos_request_list *req;
-
-	req = filp->private_data;
-	pm_qos_remove_request(req);
-	kfree(req);
-
-	return 0;
-}
-
-
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-		size_t count, loff_t *f_pos)
-{
-	s32 value;
-	unsigned long flags;
-	struct pm_qos_object *o;
-	struct pm_qos_request_list *pm_qos_req = filp->private_data;
-
-	if (!pm_qos_req)
-		return -EINVAL;
-	if (!pm_qos_request_active(pm_qos_req))
-		return -EINVAL;
-
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
-	spin_lock_irqsave(&pm_qos_lock, flags);
-	value = pm_qos_get_value(o);
-	spin_unlock_irqrestore(&pm_qos_lock, flags);
-
-	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
-}
-
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-		size_t count, loff_t *f_pos)
-{
-	s32 value;
-	struct pm_qos_request_list *pm_qos_req;
-
-	if (count == sizeof(s32)) {
-		if (copy_from_user(&value, buf, sizeof(s32)))
-			return -EFAULT;
-	} else if (count <= 11) { /* ASCII perhaps? */
-		char ascii_value[11];
-		unsigned long int ulval;
-		int ret;
-
-		if (copy_from_user(ascii_value, buf, count))
-			return -EFAULT;
-
-		if (count > 10) {
-			if (ascii_value[10] == '\n')
-				ascii_value[10] = '\0';
-			else
-				return -EINVAL;
-		} else {
-			ascii_value[count] = '\0';
-		}
-		ret = strict_strtoul(ascii_value, 16, &ulval);
-		if (ret) {
-			pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
-			return -EINVAL;
-		}
-		value = (s32)lower_32_bits(ulval);
-	} else {
-		return -EINVAL;
-	}
-
-	pm_qos_req = filp->private_data;
-	pm_qos_update_request(pm_qos_req, value);
-
-	return count;
-}
-
-
-static int __init pm_qos_power_init(void)
-{
-	int ret = 0;
-
-	ret = register_pm_qos_misc(&cpu_dma_pm_qos);
-	if (ret < 0) {
-		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");
-		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");
-
-	return ret;
-}
-
-late_initcall(pm_qos_power_init);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 866f269..bb771e9 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -19,7 +19,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/inetdevice.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d595265..f07705d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -17,7 +17,7 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/crc32.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 58ffa7d..41393c4 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -14,7 +14,7 @@
 
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <net/sch_generic.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 1c6be91..c74e228 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,7 +23,7 @@
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
 #include <sound/core.h>
-- 
1.7.2.5


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

* [PATCH 02/13] PM: add a per-device wake-up latency constraints plist
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
  2011-07-28  8:30 ` [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos jean.pihet
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Add the field latency_constraints 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 06f09bf..dad2eb9 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,6 +97,7 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
+	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 411e4f4..23c85f1 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>
@@ -463,6 +464,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
+	struct plist_head	latency_constraints;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
-- 
1.7.2.5

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

* [PATCH 02/13] PM: add a per-device wake-up latency constraints plist
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (2 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 02/13] PM: add a per-device wake-up latency constraints plist jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-29 21:58   ` Rafael J. Wysocki
  2011-07-29 21:58   ` Rafael J. Wysocki
  2011-07-28  8:30 ` [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints jean.pihet
                   ` (24 subsequent siblings)
  28 siblings, 2 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Add the field latency_constraints 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 06f09bf..dad2eb9 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,6 +97,7 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
+	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 411e4f4..23c85f1 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>
@@ -463,6 +464,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
+	struct plist_head	latency_constraints;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
-- 
1.7.2.5


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

* [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (3 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Extend the PM QoS kernel API:
- add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
constraints
- make the pm_qos_add_request API more generic by using a parameter of
type struct pm_qos_parameters
- minor clean-ups and rename of struct fields:
  . rename pm_qos_class to class and pm_qos_req to req in internal code
  . consistenly use req and params as the API parameters
  . rename struct pm_qos_request_list to struct pm_qos_request
- update the in-kernel API callers to the new API

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       |    7 +-
 drivers/net/e1000e/netdev.c            |    9 ++-
 drivers/net/wireless/ipw2x00/ipw2100.c |    8 +-
 include/linux/netdevice.h              |    2 +-
 include/linux/pm_qos.h                 |   39 ++++++----
 include/sound/pcm.h                    |    2 +-
 kernel/pm_qos.c                        |  130 +++++++++++++++++--------------
 sound/core/pcm_native.c                |    8 ++-
 10 files changed, 141 insertions(+), 119 deletions(-)

diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 2388b8e..98f7ea5 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
@@ -129,16 +128,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,
@@ -178,15 +167,6 @@ static inline int omap2_i2c_add_bus(int bus_id)
 	dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
 	pdata->flags = dev_attr->flags;
 
-	/*
-	 * 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 d53cd61..b7d3f0d 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_OMAP1_REV_2		0x20
@@ -180,8 +181,7 @@ struct omap_i2c_dev {
 	struct completion	cmd_complete;
 	struct resource		*ioarea;
 	u32			latency;	/* maximum mpu wkup latency */
-	void			(*set_mpu_wkup_lat)(struct device *dev,
-						    long latency);
+	struct pm_qos_request	pm_qos_request;
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
@@ -648,6 +648,7 @@ static int
 omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+	struct pm_qos_parameters pm_qos_params;
 	int i;
 	int r;
 
@@ -657,8 +658,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.
+	 * Used on OMAP3 Only
+	 */
+	if (cpu_is_omap34xx()) {
+		pm_qos_params.dev = dev->dev;
+		pm_qos_params.class = PM_QOS_CPU_DMA_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)));
@@ -666,8 +678,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;
@@ -1021,13 +1033,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;
@@ -1075,8 +1084,8 @@ omap_i2c_probe(struct platform_device *pdev)
 			dev->fifo_size = (dev->fifo_size / 2);
 			dev->b_hw = 1; /* Enable hardware fixes */
 		}
-		/* calculate wakeup latency constraint for MPU */
-		if (dev->set_mpu_wkup_lat != NULL)
+		/* calculate wakeup latency constraint */
+		if (cpu_is_omap34xx())
 			dev->latency = (1000000 * dev->fifo_size) /
 				       (1000 * speed / 8);
 	}
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index b3ca389..037c02c 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -69,7 +69,7 @@ struct via_camera {
 	struct mutex lock;
 	enum viacam_opstate opstate;
 	unsigned long flags;
-	struct pm_qos_request_list qos_request;
+	struct pm_qos_request qos_request;
 	/*
 	 * GPIO info for power/reset management
 	 */
@@ -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 a8a18e1..33f55f3 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 d9df575..6a41efc 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -174,7 +174,7 @@ that only one external action is invoked at a time.
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 
-static struct pm_qos_request_list ipw2100_pm_qos_req;
+static struct pm_qos_request ipw2100_pm_qos_req;
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
@@ -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/netdevice.h b/include/linux/netdevice.h
index cc1eb9e..82f01d9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -999,7 +999,7 @@ struct net_device {
 	 */
 	char			name[IFNAMSIZ];
 
-	struct pm_qos_request_list pm_qos_req;
+	struct pm_qos_request pm_qos_req;
 
 	/* device name hash chain */
 	struct hlist_node	name_hlist;
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 9cc0224..a2e4409 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -8,31 +8,40 @@
 #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_LATENCY		2
+#define PM_QOS_NETWORK_LATENCY		3
+#define PM_QOS_NETWORK_THROUGHPUT	4
 
-#define PM_QOS_NUM_CLASSES 4
+#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_DEV_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 pm_qos_request {
 	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);
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		s32 new_value);
-void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
+struct pm_qos_parameters {
+	int class;
+	struct device *dev;
+	s32 value;
+};
+
+void pm_qos_add_request(struct pm_qos_request *req,
+			struct pm_qos_parameters *params);
+void pm_qos_update_request(struct pm_qos_request *req, s32 new_value);
+void pm_qos_remove_request(struct pm_qos_request *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_active(struct pm_qos_request_list *req);
+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 *req);
 
 #endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 1204f17..d3b068f 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -373,7 +373,7 @@ struct snd_pcm_substream {
 	int number;
 	char name[32];			/* substream name */
 	int stream;			/* stream (direction) */
-	struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
+	struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
 	size_t buffer_bytes_max;	/* limit ring buffer size */
 	struct snd_dma_buffer dma_buffer;
 	unsigned int dma_buf_id;
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 3bf69f1..4ede3cd 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -82,6 +82,16 @@ static struct pm_qos_object cpu_dma_pm_qos = {
 	.type = PM_QOS_MIN,
 };
 
+static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
+static struct pm_qos_object dev_pm_qos = {
+	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
+	.notifiers = &dev_lat_notifier,
+	.name = "dev_latency",
+	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_DEV_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 +117,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_pm_qos,
 	&network_lat_pm_qos,
 	&network_throughput_pm_qos
 };
@@ -212,132 +223,132 @@ static int find_pm_qos_object_by_minor(int minor)
 
 /**
  * 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]);
+	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)
+int pm_qos_request_active(struct pm_qos_request *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
+ * @req: pointer to a preallocated handle
+ * @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
+ * for the class of parameters and initializes the pm_qos_request
  * 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 *req,
+			struct pm_qos_parameters *params)
 {
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	struct pm_qos_object *o =  pm_qos_array[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_request_active(req)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
+			"added request\n");
 		return;
 	}
-	if (value == PM_QOS_DEFAULT_VALUE)
+	if (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 = params->value;
+	plist_node_init(&req->list, new_value);
+	req->class = params->class;
+	req->dev = params->dev;
+	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
 /**
  * pm_qos_update_request - modifies an existing qos request
- * @pm_qos_req : handle to list element holding a pm_qos request to use
+ * @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.
  */
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-			   s32 new_value)
+void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 {
 	s32 temp;
 	struct pm_qos_object *o;
 
-	if (!pm_qos_req) /*guard against callers passing in null */
+	if (!req) /*guard against callers passing in null */
 		return;
 
-	if (!pm_qos_request_active(pm_qos_req)) {
+	if (!pm_qos_request_active(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];
+	o = pm_qos_array[req->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);
+	if (temp != req->list.prio)
+		update_target(o, &req->list, 0, temp);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
 /**
  * pm_qos_remove_request - modifies an existing qos request
- * @pm_qos_req: handle to request list element
+ * @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)
+void pm_qos_remove_request(struct pm_qos_request *req)
 {
 	struct pm_qos_object *o;
 
-	if (pm_qos_req == NULL)
+	if (req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
 
-	if (!pm_qos_request_active(pm_qos_req)) {
+	if (!pm_qos_request_active(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);
-	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
+	o = pm_qos_array[req->class];
+	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
+	memset(req, 0, sizeof(*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 +356,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 +375,16 @@ 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 *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)
@@ -383,7 +395,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
 
 static int pm_qos_power_release(struct inode *inode, struct file *filp)
 {
-	struct pm_qos_request_list *req;
+	struct pm_qos_request *req;
 
 	req = filp->private_data;
 	pm_qos_remove_request(req);
@@ -399,14 +411,14 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	s32 value;
 	unsigned long flags;
 	struct pm_qos_object *o;
-	struct pm_qos_request_list *pm_qos_req = filp->private_data;
+	struct pm_qos_request *req = filp->private_data;
 
-	if (!pm_qos_req)
+	if (!req)
 		return -EINVAL;
-	if (!pm_qos_request_active(pm_qos_req))
+	if (!pm_qos_request_active(req))
 		return -EINVAL;
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	o = pm_qos_array[req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	value = pm_qos_get_value(o);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -418,7 +430,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
 		size_t count, loff_t *f_pos)
 {
 	s32 value;
-	struct pm_qos_request_list *pm_qos_req;
+	struct pm_qos_request *req;
 
 	if (count == sizeof(s32)) {
 		if (copy_from_user(&value, buf, sizeof(s32)))
@@ -449,8 +461,8 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
 		return -EINVAL;
 	}
 
-	pm_qos_req = filp->private_data;
-	pm_qos_update_request(pm_qos_req, value);
+	req = filp->private_data;
+	pm_qos_update_request(req, value);
 
 	return count;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c74e228..fb05f37 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.2.5

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

* [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (4 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-29 22:55   ` Rafael J. Wysocki
                     ` (3 more replies)
  2011-07-28  8:30 ` [PATCH 04/13] PM: QoS: implement the " jean.pihet
                   ` (22 subsequent siblings)
  28 siblings, 4 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Extend the PM QoS kernel API:
- add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
constraints
- make the pm_qos_add_request API more generic by using a parameter of
type struct pm_qos_parameters
- minor clean-ups and rename of struct fields:
  . rename pm_qos_class to class and pm_qos_req to req in internal code
  . consistenly use req and params as the API parameters
  . rename struct pm_qos_request_list to struct pm_qos_request
- update the in-kernel API callers to the new API

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       |    7 +-
 drivers/net/e1000e/netdev.c            |    9 ++-
 drivers/net/wireless/ipw2x00/ipw2100.c |    8 +-
 include/linux/netdevice.h              |    2 +-
 include/linux/pm_qos.h                 |   39 ++++++----
 include/sound/pcm.h                    |    2 +-
 kernel/pm_qos.c                        |  130 +++++++++++++++++--------------
 sound/core/pcm_native.c                |    8 ++-
 10 files changed, 141 insertions(+), 119 deletions(-)

diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 2388b8e..98f7ea5 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
@@ -129,16 +128,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,
@@ -178,15 +167,6 @@ static inline int omap2_i2c_add_bus(int bus_id)
 	dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
 	pdata->flags = dev_attr->flags;
 
-	/*
-	 * 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 d53cd61..b7d3f0d 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_OMAP1_REV_2		0x20
@@ -180,8 +181,7 @@ struct omap_i2c_dev {
 	struct completion	cmd_complete;
 	struct resource		*ioarea;
 	u32			latency;	/* maximum mpu wkup latency */
-	void			(*set_mpu_wkup_lat)(struct device *dev,
-						    long latency);
+	struct pm_qos_request	pm_qos_request;
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
@@ -648,6 +648,7 @@ static int
 omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+	struct pm_qos_parameters pm_qos_params;
 	int i;
 	int r;
 
@@ -657,8 +658,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.
+	 * Used on OMAP3 Only
+	 */
+	if (cpu_is_omap34xx()) {
+		pm_qos_params.dev = dev->dev;
+		pm_qos_params.class = PM_QOS_CPU_DMA_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)));
@@ -666,8 +678,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;
@@ -1021,13 +1033,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;
@@ -1075,8 +1084,8 @@ omap_i2c_probe(struct platform_device *pdev)
 			dev->fifo_size = (dev->fifo_size / 2);
 			dev->b_hw = 1; /* Enable hardware fixes */
 		}
-		/* calculate wakeup latency constraint for MPU */
-		if (dev->set_mpu_wkup_lat != NULL)
+		/* calculate wakeup latency constraint */
+		if (cpu_is_omap34xx())
 			dev->latency = (1000000 * dev->fifo_size) /
 				       (1000 * speed / 8);
 	}
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index b3ca389..037c02c 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -69,7 +69,7 @@ struct via_camera {
 	struct mutex lock;
 	enum viacam_opstate opstate;
 	unsigned long flags;
-	struct pm_qos_request_list qos_request;
+	struct pm_qos_request qos_request;
 	/*
 	 * GPIO info for power/reset management
 	 */
@@ -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 a8a18e1..33f55f3 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 d9df575..6a41efc 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -174,7 +174,7 @@ that only one external action is invoked at a time.
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 
-static struct pm_qos_request_list ipw2100_pm_qos_req;
+static struct pm_qos_request ipw2100_pm_qos_req;
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
@@ -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/netdevice.h b/include/linux/netdevice.h
index cc1eb9e..82f01d9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -999,7 +999,7 @@ struct net_device {
 	 */
 	char			name[IFNAMSIZ];
 
-	struct pm_qos_request_list pm_qos_req;
+	struct pm_qos_request pm_qos_req;
 
 	/* device name hash chain */
 	struct hlist_node	name_hlist;
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 9cc0224..a2e4409 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -8,31 +8,40 @@
 #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_LATENCY		2
+#define PM_QOS_NETWORK_LATENCY		3
+#define PM_QOS_NETWORK_THROUGHPUT	4
 
-#define PM_QOS_NUM_CLASSES 4
+#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_DEV_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 pm_qos_request {
 	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);
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		s32 new_value);
-void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
+struct pm_qos_parameters {
+	int class;
+	struct device *dev;
+	s32 value;
+};
+
+void pm_qos_add_request(struct pm_qos_request *req,
+			struct pm_qos_parameters *params);
+void pm_qos_update_request(struct pm_qos_request *req, s32 new_value);
+void pm_qos_remove_request(struct pm_qos_request *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_active(struct pm_qos_request_list *req);
+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 *req);
 
 #endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 1204f17..d3b068f 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -373,7 +373,7 @@ struct snd_pcm_substream {
 	int number;
 	char name[32];			/* substream name */
 	int stream;			/* stream (direction) */
-	struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
+	struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
 	size_t buffer_bytes_max;	/* limit ring buffer size */
 	struct snd_dma_buffer dma_buffer;
 	unsigned int dma_buf_id;
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 3bf69f1..4ede3cd 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -82,6 +82,16 @@ static struct pm_qos_object cpu_dma_pm_qos = {
 	.type = PM_QOS_MIN,
 };
 
+static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
+static struct pm_qos_object dev_pm_qos = {
+	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
+	.notifiers = &dev_lat_notifier,
+	.name = "dev_latency",
+	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_DEV_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 +117,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_pm_qos,
 	&network_lat_pm_qos,
 	&network_throughput_pm_qos
 };
@@ -212,132 +223,132 @@ static int find_pm_qos_object_by_minor(int minor)
 
 /**
  * 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]);
+	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)
+int pm_qos_request_active(struct pm_qos_request *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
+ * @req: pointer to a preallocated handle
+ * @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
+ * for the class of parameters and initializes the pm_qos_request
  * 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 *req,
+			struct pm_qos_parameters *params)
 {
-	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	struct pm_qos_object *o =  pm_qos_array[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_request_active(req)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
+			"added request\n");
 		return;
 	}
-	if (value == PM_QOS_DEFAULT_VALUE)
+	if (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 = params->value;
+	plist_node_init(&req->list, new_value);
+	req->class = params->class;
+	req->dev = params->dev;
+	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
 /**
  * pm_qos_update_request - modifies an existing qos request
- * @pm_qos_req : handle to list element holding a pm_qos request to use
+ * @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.
  */
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-			   s32 new_value)
+void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 {
 	s32 temp;
 	struct pm_qos_object *o;
 
-	if (!pm_qos_req) /*guard against callers passing in null */
+	if (!req) /*guard against callers passing in null */
 		return;
 
-	if (!pm_qos_request_active(pm_qos_req)) {
+	if (!pm_qos_request_active(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];
+	o = pm_qos_array[req->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);
+	if (temp != req->list.prio)
+		update_target(o, &req->list, 0, temp);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
 /**
  * pm_qos_remove_request - modifies an existing qos request
- * @pm_qos_req: handle to request list element
+ * @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)
+void pm_qos_remove_request(struct pm_qos_request *req)
 {
 	struct pm_qos_object *o;
 
-	if (pm_qos_req == NULL)
+	if (req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
 
-	if (!pm_qos_request_active(pm_qos_req)) {
+	if (!pm_qos_request_active(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);
-	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
+	o = pm_qos_array[req->class];
+	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
+	memset(req, 0, sizeof(*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 +356,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 +375,16 @@ 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 *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)
@@ -383,7 +395,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
 
 static int pm_qos_power_release(struct inode *inode, struct file *filp)
 {
-	struct pm_qos_request_list *req;
+	struct pm_qos_request *req;
 
 	req = filp->private_data;
 	pm_qos_remove_request(req);
@@ -399,14 +411,14 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	s32 value;
 	unsigned long flags;
 	struct pm_qos_object *o;
-	struct pm_qos_request_list *pm_qos_req = filp->private_data;
+	struct pm_qos_request *req = filp->private_data;
 
-	if (!pm_qos_req)
+	if (!req)
 		return -EINVAL;
-	if (!pm_qos_request_active(pm_qos_req))
+	if (!pm_qos_request_active(req))
 		return -EINVAL;
 
-	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	o = pm_qos_array[req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
 	value = pm_qos_get_value(o);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -418,7 +430,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
 		size_t count, loff_t *f_pos)
 {
 	s32 value;
-	struct pm_qos_request_list *pm_qos_req;
+	struct pm_qos_request *req;
 
 	if (count == sizeof(s32)) {
 		if (copy_from_user(&value, buf, sizeof(s32)))
@@ -449,8 +461,8 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
 		return -EINVAL;
 	}
 
-	pm_qos_req = filp->private_data;
-	pm_qos_update_request(pm_qos_req, value);
+	req = filp->private_data;
+	pm_qos_update_request(req, value);
 
 	return count;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c74e228..fb05f37 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.2.5


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

* [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (5 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Re-design the PM QoS implementation to support the per-device
constraints:

- Define a pm_qos_constraints struct for the storage of the constraints
list and associated values (target_value, default_value, type ...).

- Update the pm_qos_object struct with the information related to a
PM QoS class: ptr to constraints list, notifer ptr, name ...

- Each PM QoS class statically declare objects for pm_qos_object and
pm_qos_constraints. The only exception is the devices constraints, cf. below.

- The device constraints class is statically declaring a pm_qos_object. The
pm_qos_constraints are per-device and so are embedded into the device struct.

- The PM QoS internal functions are updated to operate on the pm_qos_constraints
structs for the constraints management, and on pm_qos_object for other the PM QoS
functionality (notifiers, export as misc devices...).

- The PM QoS events notification callbacks are passing the full constraint
request data in order for the callees to have access to it. The current use
is for the platform low-level code to access the target device of the constraint

- User space API: the PM QoS classes -excepted PM_QOS_DEV_LATENCY- are exporting
a MISC entry in /dev. PM_QOS_DEV_LATENCY shall export a per-device sysfs entry, this
support is coming as a subsequent patch.

- Misc fixes to improve code readability:
  . rename of fields names (request, list, constraints, class),
  . simplification of the in-kernel API implementation. The main logic part is
    now implemented in the update_target function.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 drivers/base/power/main.c |    7 +-
 include/linux/pm.h        |    3 +-
 include/linux/pm_qos.h    |   23 ++++-
 kernel/pm_qos.c           |  248 +++++++++++++++++++++++++-------------------
 4 files changed, 170 insertions(+), 111 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index dad2eb9..360c2c0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
-	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+	dev->power.latency_constraints.target_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.default_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.type = PM_QOS_MIN;
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 23c85f1..35e48a3 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -28,6 +28,7 @@
 #include <linux/wait.h>
 #include <linux/timer.h>
 #include <linux/completion.h>
+#include <linux/pm_qos.h>
 
 /*
  * Callbacks for platform drivers to implement.
@@ -464,7 +465,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
-	struct plist_head	latency_constraints;
+	struct pm_qos_constraints	latency_constraints;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index a2e4409..d72b16b 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -6,7 +6,6 @@
  */
 #include <linux/plist.h>
 #include <linux/notifier.h>
-#include <linux/miscdevice.h>
 
 #define PM_QOS_RESERVED			0
 #define PM_QOS_CPU_DMA_LATENCY		1
@@ -22,8 +21,28 @@
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 
+enum pm_qos_type {
+	PM_QOS_MAX,		/* return the largest value */
+	PM_QOS_MIN		/* return the smallest value */
+};
+
+struct pm_qos_constraints {
+	struct plist_head list;
+	/*
+	 * Do not change target_value to 64 bit in order to guarantee
+	 * accesses atomicity
+	 */
+	s32 target_value;
+	s32 default_value;
+	enum pm_qos_type type;
+};
+
+/*
+ * Struct that is pre-allocated by the caller.
+ * The handle is kept for future use (update, removal)
+ */
 struct pm_qos_request {
-	struct plist_node list;
+	struct plist_node node;
 	int class;
 	struct device *dev;
 };
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 4ede3cd..7edc6d0 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -49,71 +49,81 @@
  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
  * held, taken with _irqsave.  One lock to rule them all
  */
-enum pm_qos_type {
-	PM_QOS_MAX,		/* return the largest value */
-	PM_QOS_MIN		/* return the smallest value */
+
+enum pm_qos_req_action {
+	PM_QOS_ADD_REQ,
+	PM_QOS_UPDATE_REQ,
+	PM_QOS_REMOVE_REQ
 };
 
-/*
- * Note: The lockless read path depends on the CPU accessing
- * target_value atomically.  Atomic access is only guaranteed on all CPU
- * types linux supports for 32 bit quantites
- */
 struct pm_qos_object {
-	struct plist_head requests;
+	struct pm_qos_constraints *constraints;
 	struct blocking_notifier_head *notifiers;
 	struct miscdevice pm_qos_power_miscdev;
 	char *name;
-	s32 target_value;	/* Do not change to 64 bit */
-	s32 default_value;
-	enum pm_qos_type type;
 };
 
 static DEFINE_SPINLOCK(pm_qos_lock);
 
 static struct pm_qos_object null_pm_qos;
+
+/* CPU/DMA latency constraints PM QoS object */
+static struct pm_qos_constraints cpu_dma_constraints = {
+	.list = PLIST_HEAD_INIT(cpu_dma_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN,
+};
 static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
 static struct pm_qos_object cpu_dma_pm_qos = {
-	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
+	.constraints = &cpu_dma_constraints,
 	.notifiers = &cpu_dma_lat_notifier,
 	.name = "cpu_dma_latency",
-	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN,
 };
 
+/*
+ * Per-device latency constraints PM QoS object
+ *
+ * The constraints are stored in the device struct data.
+ * No misc device is exported to /dev, instead the user space API
+ * shall use a per-device /sysfs entry.
+ */
 static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
 static struct pm_qos_object dev_pm_qos = {
-	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
+	.constraints = NULL,
 	.notifiers = &dev_lat_notifier,
+	.pm_qos_power_miscdev = { .minor = -1 },
 	.name = "dev_latency",
-	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN,
 };
 
+/* Network latency constraints PM QoS object */
+static struct pm_qos_constraints network_lat_constraints = {
+	.list = PLIST_HEAD_INIT(network_lat_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_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),
+	.constraints = &network_lat_constraints,
 	.notifiers = &network_lat_notifier,
 	.name = "network_latency",
-	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN
 };
 
-
+/* Network throughput constraints PM QoS object */
+static struct pm_qos_constraints network_tput_constraints = {
+	.list = PLIST_HEAD_INIT(network_tput_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.type = PM_QOS_MAX,
+};
 static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
 static struct pm_qos_object network_throughput_pm_qos = {
-	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
+	.constraints = &network_tput_constraints,
 	.notifiers = &network_throughput_notifier,
 	.name = "network_throughput",
-	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.type = PM_QOS_MAX,
 };
 
-
 static struct pm_qos_object *pm_qos_array[] = {
 	&null_pm_qos,
 	&cpu_dma_pm_qos,
@@ -138,17 +148,17 @@ static const struct file_operations pm_qos_power_fops = {
 };
 
 /* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_object *o)
+static inline int pm_qos_get_value(struct pm_qos_constraints *c)
 {
-	if (plist_head_empty(&o->requests))
-		return o->default_value;
+	if (plist_head_empty(&c->list))
+		return c->default_value;
 
-	switch (o->type) {
+	switch (c->type) {
 	case PM_QOS_MIN:
-		return plist_first(&o->requests)->prio;
+		return plist_first(&c->list)->prio;
 
 	case PM_QOS_MAX:
-		return plist_last(&o->requests)->prio;
+		return plist_last(&c->list)->prio;
 
 	default:
 		/* runtime check for not using enum */
@@ -156,69 +166,92 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
 	}
 }
 
-static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+/*
+ * pm_qos_read_value atomically reads and returns target_value.
+ * target_value is updated upon update of the constraints list, using
+ * pm_qos_set_value.
+ *
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically.  Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
+static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
 {
-	return o->target_value;
+	if (c)
+		return c->target_value;
+	else
+		return 0;
 }
 
-static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
+static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
 {
-	o->target_value = value;
+	c->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 *req,
+			  enum pm_qos_req_action action, int value)
 {
 	unsigned long flags;
-	int prev_value, curr_value;
+	int prev_value, curr_value, new_value;
+	struct pm_qos_object *o = pm_qos_array[req->class];
+	struct pm_qos_constraints *c;
+
+	switch (req->class) {
+	case PM_QOS_DEV_LATENCY:
+		if (!req->dev) {
+			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
+			return;
+		}
+		c = &req->dev->power.latency_constraints;
+		break;
+	case PM_QOS_CPU_DMA_LATENCY:
+	case PM_QOS_NETWORK_LATENCY:
+	case PM_QOS_NETWORK_THROUGHPUT:
+		c = o->constraints;
+		break;
+	case PM_QOS_RESERVED:
+	default:
+		WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
+			"req 0x%p\n", req->class, req);
+		return;
+	}
 
 	spin_lock_irqsave(&pm_qos_lock, flags);
-	prev_value = pm_qos_get_value(o);
-	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
-	if (value != PM_QOS_DEFAULT_VALUE) {
+
+	prev_value = pm_qos_get_value(c);
+	if (value == PM_QOS_DEFAULT_VALUE)
+		new_value = c->default_value;
+	else
+		new_value = value;
+
+	switch (action) {
+	case PM_QOS_REMOVE_REQ:
+		plist_del(&req->node, &c->list);
+		break;
+	case PM_QOS_UPDATE_REQ:
 		/*
 		 * to change the list, we atomically remove, reinit
 		 * with new value and add, then see if the extremal
 		 * changed
 		 */
-		plist_del(node, &o->requests);
-		plist_node_init(node, value);
-		plist_add(node, &o->requests);
-	} else if (del) {
-		plist_del(node, &o->requests);
-	} else {
-		plist_add(node, &o->requests);
+		plist_del(&req->node, &c->list);
+	case PM_QOS_ADD_REQ:
+		plist_node_init(&req->node, new_value);
+		plist_add(&req->node, &c->list);
+		break;
+	default:
+		/* no action */
+		;
 	}
-	curr_value = pm_qos_get_value(o);
-	pm_qos_set_value(o, curr_value);
+
+	curr_value = pm_qos_get_value(c);
+	pm_qos_set_value(c, 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);
-}
-
-static int register_pm_qos_misc(struct pm_qos_object *qos)
-{
-	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-	qos->pm_qos_power_miscdev.name = qos->name;
-	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
-	return misc_register(&qos->pm_qos_power_miscdev);
-}
-
-static int find_pm_qos_object_by_minor(int minor)
-{
-	int pm_qos_class;
-
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
-		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
-	}
-	return -1;
+					     req);
 }
 
 /**
@@ -229,7 +262,7 @@ static int find_pm_qos_object_by_minor(int minor)
  */
 int pm_qos_request(int class)
 {
-	return pm_qos_read_value(pm_qos_array[class]);
+	return pm_qos_read_value(pm_qos_array[class]->constraints);
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
@@ -254,22 +287,15 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
 void pm_qos_add_request(struct pm_qos_request *req,
 			struct pm_qos_parameters *params)
 {
-	struct pm_qos_object *o =  pm_qos_array[params->class];
-	int new_value;
-
 	if (pm_qos_request_active(req)) {
 		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
 			"added request\n");
 		return;
 	}
-	if (params->value == PM_QOS_DEFAULT_VALUE)
-		new_value = o->default_value;
-	else
-		new_value = params->value;
-	plist_node_init(&req->list, new_value);
+
 	req->class = params->class;
 	req->dev = params->dev;
-	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
+	update_target(req, PM_QOS_ADD_REQ, params->value);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
@@ -285,9 +311,6 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
  */
 void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 {
-	s32 temp;
-	struct pm_qos_object *o;
-
 	if (!req) /*guard against callers passing in null */
 		return;
 
@@ -296,15 +319,8 @@ void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 		return;
 	}
 
-	o = pm_qos_array[req->class];
-
-	if (new_value == PM_QOS_DEFAULT_VALUE)
-		temp = o->default_value;
-	else
-		temp = new_value;
-
-	if (temp != req->list.prio)
-		update_target(o, &req->list, 0, temp);
+	if (new_value != req->node.prio)
+		update_target(req, PM_QOS_UPDATE_REQ, new_value);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
@@ -318,8 +334,6 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
  */
 void pm_qos_remove_request(struct pm_qos_request *req)
 {
-	struct pm_qos_object *o;
-
 	if (req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
@@ -329,8 +343,8 @@ void pm_qos_remove_request(struct pm_qos_request *req)
 		return;
 	}
 
-	o = pm_qos_array[req->class];
-	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
+	update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+
 	memset(req, 0, sizeof(*req));
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_request);
@@ -373,6 +387,28 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+	qos->pm_qos_power_miscdev.name = qos->name;
+	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+	return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+	int pm_qos_class;
+
+	for (pm_qos_class = 0;
+		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+		if (minor ==
+			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+			return pm_qos_class;
+	}
+	return -1;
+}
+
 static int pm_qos_power_open(struct inode *inode, struct file *filp)
 {
 	struct pm_qos_parameters pm_qos_params;
@@ -410,7 +446,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 {
 	s32 value;
 	unsigned long flags;
-	struct pm_qos_object *o;
 	struct pm_qos_request *req = filp->private_data;
 
 	if (!req)
@@ -418,9 +453,8 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	if (!pm_qos_request_active(req))
 		return -EINVAL;
 
-	o = pm_qos_array[req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
-	value = pm_qos_get_value(o);
+	value = pm_qos_get_value(pm_qos_array[req->class]->constraints);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 
 	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
-- 
1.7.2.5

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

* [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (6 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 04/13] PM: QoS: implement the " jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-30 22:30   ` Rafael J. Wysocki
  2011-07-30 22:30   ` Rafael J. Wysocki
  2011-07-28  8:30 ` [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices jean.pihet
                   ` (20 subsequent siblings)
  28 siblings, 2 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Re-design the PM QoS implementation to support the per-device
constraints:

- Define a pm_qos_constraints struct for the storage of the constraints
list and associated values (target_value, default_value, type ...).

- Update the pm_qos_object struct with the information related to a
PM QoS class: ptr to constraints list, notifer ptr, name ...

- Each PM QoS class statically declare objects for pm_qos_object and
pm_qos_constraints. The only exception is the devices constraints, cf. below.

- The device constraints class is statically declaring a pm_qos_object. The
pm_qos_constraints are per-device and so are embedded into the device struct.

- The PM QoS internal functions are updated to operate on the pm_qos_constraints
structs for the constraints management, and on pm_qos_object for other the PM QoS
functionality (notifiers, export as misc devices...).

- The PM QoS events notification callbacks are passing the full constraint
request data in order for the callees to have access to it. The current use
is for the platform low-level code to access the target device of the constraint

- User space API: the PM QoS classes -excepted PM_QOS_DEV_LATENCY- are exporting
a MISC entry in /dev. PM_QOS_DEV_LATENCY shall export a per-device sysfs entry, this
support is coming as a subsequent patch.

- Misc fixes to improve code readability:
  . rename of fields names (request, list, constraints, class),
  . simplification of the in-kernel API implementation. The main logic part is
    now implemented in the update_target function.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 drivers/base/power/main.c |    7 +-
 include/linux/pm.h        |    3 +-
 include/linux/pm_qos.h    |   23 ++++-
 kernel/pm_qos.c           |  248 +++++++++++++++++++++++++-------------------
 4 files changed, 170 insertions(+), 111 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index dad2eb9..360c2c0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
-	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+	dev->power.latency_constraints.target_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.default_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.type = PM_QOS_MIN;
 }
 
 /**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 23c85f1..35e48a3 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -28,6 +28,7 @@
 #include <linux/wait.h>
 #include <linux/timer.h>
 #include <linux/completion.h>
+#include <linux/pm_qos.h>
 
 /*
  * Callbacks for platform drivers to implement.
@@ -464,7 +465,7 @@ struct dev_pm_info {
 	unsigned long		accounting_timestamp;
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
-	struct plist_head	latency_constraints;
+	struct pm_qos_constraints	latency_constraints;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index a2e4409..d72b16b 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -6,7 +6,6 @@
  */
 #include <linux/plist.h>
 #include <linux/notifier.h>
-#include <linux/miscdevice.h>
 
 #define PM_QOS_RESERVED			0
 #define PM_QOS_CPU_DMA_LATENCY		1
@@ -22,8 +21,28 @@
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 
+enum pm_qos_type {
+	PM_QOS_MAX,		/* return the largest value */
+	PM_QOS_MIN		/* return the smallest value */
+};
+
+struct pm_qos_constraints {
+	struct plist_head list;
+	/*
+	 * Do not change target_value to 64 bit in order to guarantee
+	 * accesses atomicity
+	 */
+	s32 target_value;
+	s32 default_value;
+	enum pm_qos_type type;
+};
+
+/*
+ * Struct that is pre-allocated by the caller.
+ * The handle is kept for future use (update, removal)
+ */
 struct pm_qos_request {
-	struct plist_node list;
+	struct plist_node node;
 	int class;
 	struct device *dev;
 };
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 4ede3cd..7edc6d0 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -49,71 +49,81 @@
  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
  * held, taken with _irqsave.  One lock to rule them all
  */
-enum pm_qos_type {
-	PM_QOS_MAX,		/* return the largest value */
-	PM_QOS_MIN		/* return the smallest value */
+
+enum pm_qos_req_action {
+	PM_QOS_ADD_REQ,
+	PM_QOS_UPDATE_REQ,
+	PM_QOS_REMOVE_REQ
 };
 
-/*
- * Note: The lockless read path depends on the CPU accessing
- * target_value atomically.  Atomic access is only guaranteed on all CPU
- * types linux supports for 32 bit quantites
- */
 struct pm_qos_object {
-	struct plist_head requests;
+	struct pm_qos_constraints *constraints;
 	struct blocking_notifier_head *notifiers;
 	struct miscdevice pm_qos_power_miscdev;
 	char *name;
-	s32 target_value;	/* Do not change to 64 bit */
-	s32 default_value;
-	enum pm_qos_type type;
 };
 
 static DEFINE_SPINLOCK(pm_qos_lock);
 
 static struct pm_qos_object null_pm_qos;
+
+/* CPU/DMA latency constraints PM QoS object */
+static struct pm_qos_constraints cpu_dma_constraints = {
+	.list = PLIST_HEAD_INIT(cpu_dma_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+	.type = PM_QOS_MIN,
+};
 static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
 static struct pm_qos_object cpu_dma_pm_qos = {
-	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
+	.constraints = &cpu_dma_constraints,
 	.notifiers = &cpu_dma_lat_notifier,
 	.name = "cpu_dma_latency",
-	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN,
 };
 
+/*
+ * Per-device latency constraints PM QoS object
+ *
+ * The constraints are stored in the device struct data.
+ * No misc device is exported to /dev, instead the user space API
+ * shall use a per-device /sysfs entry.
+ */
 static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
 static struct pm_qos_object dev_pm_qos = {
-	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
+	.constraints = NULL,
 	.notifiers = &dev_lat_notifier,
+	.pm_qos_power_miscdev = { .minor = -1 },
 	.name = "dev_latency",
-	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN,
 };
 
+/* Network latency constraints PM QoS object */
+static struct pm_qos_constraints network_lat_constraints = {
+	.list = PLIST_HEAD_INIT(network_lat_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_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),
+	.constraints = &network_lat_constraints,
 	.notifiers = &network_lat_notifier,
 	.name = "network_latency",
-	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
-	.type = PM_QOS_MIN
 };
 
-
+/* Network throughput constraints PM QoS object */
+static struct pm_qos_constraints network_tput_constraints = {
+	.list = PLIST_HEAD_INIT(network_tput_constraints.list, pm_qos_lock),
+	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+	.type = PM_QOS_MAX,
+};
 static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
 static struct pm_qos_object network_throughput_pm_qos = {
-	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
+	.constraints = &network_tput_constraints,
 	.notifiers = &network_throughput_notifier,
 	.name = "network_throughput",
-	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
-	.type = PM_QOS_MAX,
 };
 
-
 static struct pm_qos_object *pm_qos_array[] = {
 	&null_pm_qos,
 	&cpu_dma_pm_qos,
@@ -138,17 +148,17 @@ static const struct file_operations pm_qos_power_fops = {
 };
 
 /* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_object *o)
+static inline int pm_qos_get_value(struct pm_qos_constraints *c)
 {
-	if (plist_head_empty(&o->requests))
-		return o->default_value;
+	if (plist_head_empty(&c->list))
+		return c->default_value;
 
-	switch (o->type) {
+	switch (c->type) {
 	case PM_QOS_MIN:
-		return plist_first(&o->requests)->prio;
+		return plist_first(&c->list)->prio;
 
 	case PM_QOS_MAX:
-		return plist_last(&o->requests)->prio;
+		return plist_last(&c->list)->prio;
 
 	default:
 		/* runtime check for not using enum */
@@ -156,69 +166,92 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
 	}
 }
 
-static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+/*
+ * pm_qos_read_value atomically reads and returns target_value.
+ * target_value is updated upon update of the constraints list, using
+ * pm_qos_set_value.
+ *
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically.  Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
+static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
 {
-	return o->target_value;
+	if (c)
+		return c->target_value;
+	else
+		return 0;
 }
 
-static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
+static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
 {
-	o->target_value = value;
+	c->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 *req,
+			  enum pm_qos_req_action action, int value)
 {
 	unsigned long flags;
-	int prev_value, curr_value;
+	int prev_value, curr_value, new_value;
+	struct pm_qos_object *o = pm_qos_array[req->class];
+	struct pm_qos_constraints *c;
+
+	switch (req->class) {
+	case PM_QOS_DEV_LATENCY:
+		if (!req->dev) {
+			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
+			return;
+		}
+		c = &req->dev->power.latency_constraints;
+		break;
+	case PM_QOS_CPU_DMA_LATENCY:
+	case PM_QOS_NETWORK_LATENCY:
+	case PM_QOS_NETWORK_THROUGHPUT:
+		c = o->constraints;
+		break;
+	case PM_QOS_RESERVED:
+	default:
+		WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
+			"req 0x%p\n", req->class, req);
+		return;
+	}
 
 	spin_lock_irqsave(&pm_qos_lock, flags);
-	prev_value = pm_qos_get_value(o);
-	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
-	if (value != PM_QOS_DEFAULT_VALUE) {
+
+	prev_value = pm_qos_get_value(c);
+	if (value == PM_QOS_DEFAULT_VALUE)
+		new_value = c->default_value;
+	else
+		new_value = value;
+
+	switch (action) {
+	case PM_QOS_REMOVE_REQ:
+		plist_del(&req->node, &c->list);
+		break;
+	case PM_QOS_UPDATE_REQ:
 		/*
 		 * to change the list, we atomically remove, reinit
 		 * with new value and add, then see if the extremal
 		 * changed
 		 */
-		plist_del(node, &o->requests);
-		plist_node_init(node, value);
-		plist_add(node, &o->requests);
-	} else if (del) {
-		plist_del(node, &o->requests);
-	} else {
-		plist_add(node, &o->requests);
+		plist_del(&req->node, &c->list);
+	case PM_QOS_ADD_REQ:
+		plist_node_init(&req->node, new_value);
+		plist_add(&req->node, &c->list);
+		break;
+	default:
+		/* no action */
+		;
 	}
-	curr_value = pm_qos_get_value(o);
-	pm_qos_set_value(o, curr_value);
+
+	curr_value = pm_qos_get_value(c);
+	pm_qos_set_value(c, 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);
-}
-
-static int register_pm_qos_misc(struct pm_qos_object *qos)
-{
-	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-	qos->pm_qos_power_miscdev.name = qos->name;
-	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
-	return misc_register(&qos->pm_qos_power_miscdev);
-}
-
-static int find_pm_qos_object_by_minor(int minor)
-{
-	int pm_qos_class;
-
-	for (pm_qos_class = 0;
-		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
-		if (minor ==
-			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-			return pm_qos_class;
-	}
-	return -1;
+					     req);
 }
 
 /**
@@ -229,7 +262,7 @@ static int find_pm_qos_object_by_minor(int minor)
  */
 int pm_qos_request(int class)
 {
-	return pm_qos_read_value(pm_qos_array[class]);
+	return pm_qos_read_value(pm_qos_array[class]->constraints);
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
@@ -254,22 +287,15 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
 void pm_qos_add_request(struct pm_qos_request *req,
 			struct pm_qos_parameters *params)
 {
-	struct pm_qos_object *o =  pm_qos_array[params->class];
-	int new_value;
-
 	if (pm_qos_request_active(req)) {
 		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
 			"added request\n");
 		return;
 	}
-	if (params->value == PM_QOS_DEFAULT_VALUE)
-		new_value = o->default_value;
-	else
-		new_value = params->value;
-	plist_node_init(&req->list, new_value);
+
 	req->class = params->class;
 	req->dev = params->dev;
-	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
+	update_target(req, PM_QOS_ADD_REQ, params->value);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
@@ -285,9 +311,6 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
  */
 void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 {
-	s32 temp;
-	struct pm_qos_object *o;
-
 	if (!req) /*guard against callers passing in null */
 		return;
 
@@ -296,15 +319,8 @@ void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
 		return;
 	}
 
-	o = pm_qos_array[req->class];
-
-	if (new_value == PM_QOS_DEFAULT_VALUE)
-		temp = o->default_value;
-	else
-		temp = new_value;
-
-	if (temp != req->list.prio)
-		update_target(o, &req->list, 0, temp);
+	if (new_value != req->node.prio)
+		update_target(req, PM_QOS_UPDATE_REQ, new_value);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
@@ -318,8 +334,6 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
  */
 void pm_qos_remove_request(struct pm_qos_request *req)
 {
-	struct pm_qos_object *o;
-
 	if (req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
@@ -329,8 +343,8 @@ void pm_qos_remove_request(struct pm_qos_request *req)
 		return;
 	}
 
-	o = pm_qos_array[req->class];
-	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
+	update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+
 	memset(req, 0, sizeof(*req));
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_request);
@@ -373,6 +387,28 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+	qos->pm_qos_power_miscdev.name = qos->name;
+	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+	return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+	int pm_qos_class;
+
+	for (pm_qos_class = 0;
+		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+		if (minor ==
+			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+			return pm_qos_class;
+	}
+	return -1;
+}
+
 static int pm_qos_power_open(struct inode *inode, struct file *filp)
 {
 	struct pm_qos_parameters pm_qos_params;
@@ -410,7 +446,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 {
 	s32 value;
 	unsigned long flags;
-	struct pm_qos_object *o;
 	struct pm_qos_request *req = filp->private_data;
 
 	if (!req)
@@ -418,9 +453,8 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
 	if (!pm_qos_request_active(req))
 		return -EINVAL;
 
-	o = pm_qos_array[req->class];
 	spin_lock_irqsave(&pm_qos_lock, flags);
-	value = pm_qos_get_value(o);
+	value = pm_qos_get_value(pm_qos_array[req->class]->constraints);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 
 	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
-- 
1.7.2.5


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

* [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (7 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The devices latency constraints class of PM QoS is storing the
constraints list in the device dev_pm_info struct.

This patch adds the init and de-init of the per-device constraints
list in order to support the dynamic insertion and removal
of the devices in the system.

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

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 360c2c0..c86f97c 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,12 +97,8 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
-	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
-	dev->power.latency_constraints.target_value =
-					PM_QOS_DEV_LAT_DEFAULT_VALUE;
-	dev->power.latency_constraints.default_value =
-					PM_QOS_DEV_LAT_DEFAULT_VALUE;
-	dev->power.latency_constraints.type = PM_QOS_MIN;
+	/* Call PM QoS to init the per-device latency constraints */
+	pm_qos_dev_constraints_init(dev);
 }
 
 /**
@@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
 {
 	pr_debug("PM: Removing info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
+	/* Call PM QoS to de-init the per-device latency constraints */
+	pm_qos_dev_constraints_deinit(dev);
 	complete_all(&dev->power.completion);
 	mutex_lock(&dpm_list_mtx);
 	list_del_init(&dev->power.entry);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 35e48a3..3ed53be 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -466,6 +466,7 @@ struct dev_pm_info {
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
 	struct pm_qos_constraints	latency_constraints;
+	int			latency_constraints_init;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index d72b16b..4d36537 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -63,4 +63,6 @@ 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 *req);
 
+void pm_qos_dev_constraints_init(struct device *dev);
+void pm_qos_dev_constraints_deinit(struct device *dev);
 #endif
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 7edc6d0..361fc3f 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -202,6 +202,9 @@ static void update_target(struct pm_qos_request *req,
 			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
 			return;
 		}
+		/* Silently return if the device is being released */
+		if (!req->dev->power.latency_constraints_init)
+			return;
 		c = &req->dev->power.latency_constraints;
 		break;
 	case PM_QOS_CPU_DMA_LATENCY:
@@ -387,6 +390,33 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
+/* Called from the device PM subsystem at device init */
+void pm_qos_dev_constraints_init(struct device *dev)
+{
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+	dev->power.latency_constraints.target_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.default_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.type = PM_QOS_MIN;
+	dev->power.latency_constraints_init = 1;
+}
+
+/* Called from the device PM subsystem at device release */
+void pm_qos_dev_constraints_deinit(struct device *dev)
+{
+	struct pm_qos_request *req, *tmp;
+
+	dev->power.latency_constraints_init = 0;
+
+	/* Flush the constraints list for the device */
+	plist_for_each_entry_safe(req, tmp,
+				  &dev->power.latency_constraints.list,
+				  node)
+		update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+}
+
 static int register_pm_qos_misc(struct pm_qos_object *qos)
 {
 	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-- 
1.7.2.5

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

* [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (8 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-30 22:38   ` Rafael J. Wysocki
  2011-07-30 22:38   ` Rafael J. Wysocki
  2011-07-28  8:30 ` [PATCH 06/13] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
                   ` (18 subsequent siblings)
  28 siblings, 2 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The devices latency constraints class of PM QoS is storing the
constraints list in the device dev_pm_info struct.

This patch adds the init and de-init of the per-device constraints
list in order to support the dynamic insertion and removal
of the devices in the system.

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

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 360c2c0..c86f97c 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -97,12 +97,8 @@ void device_pm_add(struct device *dev)
 			dev_name(dev->parent));
 	list_add_tail(&dev->power.entry, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
-	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
-	dev->power.latency_constraints.target_value =
-					PM_QOS_DEV_LAT_DEFAULT_VALUE;
-	dev->power.latency_constraints.default_value =
-					PM_QOS_DEV_LAT_DEFAULT_VALUE;
-	dev->power.latency_constraints.type = PM_QOS_MIN;
+	/* Call PM QoS to init the per-device latency constraints */
+	pm_qos_dev_constraints_init(dev);
 }
 
 /**
@@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
 {
 	pr_debug("PM: Removing info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
+	/* Call PM QoS to de-init the per-device latency constraints */
+	pm_qos_dev_constraints_deinit(dev);
 	complete_all(&dev->power.completion);
 	mutex_lock(&dpm_list_mtx);
 	list_del_init(&dev->power.entry);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 35e48a3..3ed53be 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -466,6 +466,7 @@ struct dev_pm_info {
 	void			*subsys_data;  /* Owned by the subsystem. */
 #endif
 	struct pm_qos_constraints	latency_constraints;
+	int			latency_constraints_init;
 };
 
 extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index d72b16b..4d36537 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -63,4 +63,6 @@ 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 *req);
 
+void pm_qos_dev_constraints_init(struct device *dev);
+void pm_qos_dev_constraints_deinit(struct device *dev);
 #endif
diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
index 7edc6d0..361fc3f 100644
--- a/kernel/pm_qos.c
+++ b/kernel/pm_qos.c
@@ -202,6 +202,9 @@ static void update_target(struct pm_qos_request *req,
 			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
 			return;
 		}
+		/* Silently return if the device is being released */
+		if (!req->dev->power.latency_constraints_init)
+			return;
 		c = &req->dev->power.latency_constraints;
 		break;
 	case PM_QOS_CPU_DMA_LATENCY:
@@ -387,6 +390,33 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
 
+/* Called from the device PM subsystem at device init */
+void pm_qos_dev_constraints_init(struct device *dev)
+{
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+	dev->power.latency_constraints.target_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.default_value =
+					PM_QOS_DEV_LAT_DEFAULT_VALUE;
+	dev->power.latency_constraints.type = PM_QOS_MIN;
+	dev->power.latency_constraints_init = 1;
+}
+
+/* Called from the device PM subsystem at device release */
+void pm_qos_dev_constraints_deinit(struct device *dev)
+{
+	struct pm_qos_request *req, *tmp;
+
+	dev->power.latency_constraints_init = 0;
+
+	/* Flush the constraints list for the device */
+	plist_for_each_entry_safe(req, tmp,
+				  &dev->power.latency_constraints.list,
+				  node)
+		update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
+}
+
 static int register_pm_qos_misc(struct pm_qos_object *qos)
 {
 	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-- 
1.7.2.5


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

* [PATCH 06/13] OMAP PM: create a PM layer plugin for per-device constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (10 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 06/13] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 07/13] OMAP PM: early init of the pwrdms states jean.pihet
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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 6e6735f..5ff9f9f 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -214,6 +214,13 @@ choice
 config OMAP_PM_NOOP
 	bool "No-op/debug PM layer"
 
+config OMAP_PM_CONSTRAINTS
+	depends on PM
+	bool "Per device constraints"
+	help
+	  Select this option to enable the PM layer plugin for
+	  the per-device constraints support
+
 endchoice
 
 endmenu
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f0233e6..f2e09f1 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -32,3 +32,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
 obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+obj-$(CONFIG_OMAP_PM_CONSTRAINTS) += omap-pm-constraints.o
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
new file mode 100644
index 0000000..c8b4e4c
--- /dev/null
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -0,0 +1,363 @@
+/*
+ * omap-pm.c - OMAP power management interface
+ *
+ * This code implements the OMAP power management interface to
+ * drivers, CPUIdle, CPUFreq, and DSP Bridge.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * Interface developed by (in alphabetical order):
+ * Karthik Dasu, Tony Lindgren, Jean Pihet, Rajendra Nayak, Sakari Poussa,
+ * Veeramanikandan Raju, Anand Sawant, Igor Stoppa, Paul Walmsley,
+ * Richard Woodruff
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* Interface documentation is in mach/omap-pm.h */
+#include <plat/omap-pm.h>
+#include <plat/omap_device.h>
+
+static bool off_mode_enabled;
+static u32 dummy_context_loss_counter;
+
+/*
+ * Device-driver-originated constraints (via board-*.c files)
+ */
+
+int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the MPU to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on the MPU and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+{
+	if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+	    agent_id != OCP_TARGET_AGENT)) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min bus tput constraint: "
+			 "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+	else
+		pr_debug("OMAP PM: add min bus tput constraint: "
+			 "dev %s for agent_id %d: rate %ld KiB\n",
+			 dev_name(dev), agent_id, r);
+
+	/*
+	 * This code should model the interconnect and compute the
+	 * required clock frequency, convert that to a VDD2 OPP ID, then
+	 * set the VDD2 OPP appropriately.
+	 *
+	 * TI CDP code can call constraint_set here on the VDD2 OPP.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
+				   long t)
+{
+	if (!req_dev || !dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max device latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max device latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the device to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on that powerdomain and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.  Conceivably, this code should also determine
+	 * whether to actually disable the device clocks or not,
+	 * depending on how long it takes to re-enable the clocks.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max DMA latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max DMA latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux PM QOS params, this code should scan the
+	 * list of maximum CPU and DMA latencies and select the
+	 * smallest, then set cpu_dma_latency pm_qos_param
+	 * accordingly.
+	 *
+	 * For future Linux PM QOS params, with separate CPU and DMA
+	 * latency params, this code should just set the dma_latency param.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
+{
+	if (!dev || !c || r < 0) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	}
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min clk rate constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add min clk rate constraint: "
+			 "dev %s, rate = %ld Hz\n", dev_name(dev), r);
+
+	/*
+	 * Code in a real implementation should keep track of these
+	 * constraints on the clock, and determine the highest minimum
+	 * clock rate.  It should iterate over each OPP and determine
+	 * whether the OPP will result in a clock rate that would
+	 * satisfy this constraint (and any other PM constraint in effect
+	 * at that time).  Once it finds the lowest-voltage OPP that
+	 * meets those conditions, it should switch to it, or return
+	 * an error if the code is not capable of doing so.
+	 */
+
+	return 0;
+}
+
+/*
+ * DSP Bridge-specific constraints
+ */
+
+const struct omap_opp *omap_pm_dsp_get_opp_table(void)
+{
+	pr_debug("OMAP PM: DSP request for OPP table\n");
+
+	/*
+	 * Return DSP frequency table here:  The final item in the
+	 * array should have .rate = .opp_id = 0.
+	 */
+
+	return NULL;
+}
+
+void omap_pm_dsp_set_min_opp(u8 opp_id)
+{
+	if (opp_id == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
+
+	/*
+	 *
+	 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
+	 * can just test to see which is higher, the CPU's desired OPP
+	 * ID or the DSP's desired OPP ID, and use whichever is
+	 * highest.
+	 *
+	 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
+	 * rate is keyed on MPU speed, not the OPP ID.  So we need to
+	 * map the OPP ID to the MPU speed for use with clk_set_rate()
+	 * if it is higher than the current OPP clock rate.
+	 *
+	 */
+}
+
+
+u8 omap_pm_dsp_get_opp(void)
+{
+	pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
+
+	/*
+	 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
+	 *
+	 * CDP12.14+:
+	 * Call clk_get_rate() on the OPP custom clock, map that to an
+	 * OPP ID using the tables defined in board-*.c/chip-*.c files.
+	 */
+
+	return 0;
+}
+
+/*
+ * CPUFreq-originated constraint
+ *
+ * In the future, this should be handled by custom OPP clocktype
+ * functions.
+ */
+
+struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void)
+{
+	pr_debug("OMAP PM: CPUFreq request for frequency table\n");
+
+	/*
+	 * Return CPUFreq frequency table here: loop over
+	 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
+	 * table
+	 */
+
+	return NULL;
+}
+
+void omap_pm_cpu_set_freq(unsigned long f)
+{
+	if (f == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+		 f);
+
+	/*
+	 * For l-o dev tree, determine whether MPU freq or DSP OPP id
+	 * freq is higher.  Find the OPP ID corresponding to the
+	 * higher frequency.  Call clk_round_rate() and clk_set_rate()
+	 * on the OPP custom clock.
+	 *
+	 * CDP should just be able to set the VDD1 OPP clock rate here.
+	 */
+}
+
+unsigned long omap_pm_cpu_get_freq(void)
+{
+	pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
+
+	/*
+	 * Call clk_get_rate() on the mpu_ck.
+	 */
+
+	return 0;
+}
+
+/**
+ * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been enabled.
+ */
+void omap_pm_enable_off_mode(void)
+{
+	off_mode_enabled = true;
+}
+
+/**
+ * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been disabled.
+ */
+void omap_pm_disable_off_mode(void)
+{
+	off_mode_enabled = false;
+}
+
+/*
+ * Device context loss tracking
+ */
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	u32 count;
+
+	if (WARN_ON(!dev))
+		return 0;
+
+	if (dev->parent == &omap_device_parent) {
+		count = omap_device_get_context_loss_count(pdev);
+	} else {
+		WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context "
+			  "loss counter; device %s should be converted to "
+			  "omap_device", dev_name(dev));
+		if (off_mode_enabled)
+			dummy_context_loss_counter++;
+		count = dummy_context_loss_counter;
+	}
+
+	pr_debug("OMAP PM: context loss count for dev %s = %d\n",
+		 dev_name(dev), count);
+
+	return count;
+}
+
+#else
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	return dummy_context_loss_counter;
+}
+
+#endif
+
+/* Should be called before clk framework init */
+int __init omap_pm_if_early_init(void)
+{
+	return 0;
+}
+
+/* Must be called after clock framework is initialized */
+int __init omap_pm_if_init(void)
+{
+	return 0;
+}
+
+void omap_pm_if_exit(void)
+{
+	/* Deallocate CPUFreq frequency table here */
+}
+
-- 
1.7.2.5

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

* [PATCH 06/13] OMAP PM: create a PM layer plugin for per-device constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (9 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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 6e6735f..5ff9f9f 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -214,6 +214,13 @@ choice
 config OMAP_PM_NOOP
 	bool "No-op/debug PM layer"
 
+config OMAP_PM_CONSTRAINTS
+	depends on PM
+	bool "Per device constraints"
+	help
+	  Select this option to enable the PM layer plugin for
+	  the per-device constraints support
+
 endchoice
 
 endmenu
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f0233e6..f2e09f1 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -32,3 +32,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
 obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+obj-$(CONFIG_OMAP_PM_CONSTRAINTS) += omap-pm-constraints.o
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
new file mode 100644
index 0000000..c8b4e4c
--- /dev/null
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -0,0 +1,363 @@
+/*
+ * omap-pm.c - OMAP power management interface
+ *
+ * This code implements the OMAP power management interface to
+ * drivers, CPUIdle, CPUFreq, and DSP Bridge.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * Interface developed by (in alphabetical order):
+ * Karthik Dasu, Tony Lindgren, Jean Pihet, Rajendra Nayak, Sakari Poussa,
+ * Veeramanikandan Raju, Anand Sawant, Igor Stoppa, Paul Walmsley,
+ * Richard Woodruff
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* Interface documentation is in mach/omap-pm.h */
+#include <plat/omap-pm.h>
+#include <plat/omap_device.h>
+
+static bool off_mode_enabled;
+static u32 dummy_context_loss_counter;
+
+/*
+ * Device-driver-originated constraints (via board-*.c files)
+ */
+
+int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the MPU to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on the MPU and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+{
+	if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+	    agent_id != OCP_TARGET_AGENT)) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min bus tput constraint: "
+			 "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+	else
+		pr_debug("OMAP PM: add min bus tput constraint: "
+			 "dev %s for agent_id %d: rate %ld KiB\n",
+			 dev_name(dev), agent_id, r);
+
+	/*
+	 * This code should model the interconnect and compute the
+	 * required clock frequency, convert that to a VDD2 OPP ID, then
+	 * set the VDD2 OPP appropriately.
+	 *
+	 * TI CDP code can call constraint_set here on the VDD2 OPP.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
+				   long t)
+{
+	if (!req_dev || !dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max device latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max device latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the device to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on that powerdomain and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.  Conceivably, this code should also determine
+	 * whether to actually disable the device clocks or not,
+	 * depending on how long it takes to re-enable the clocks.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max DMA latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max DMA latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux PM QOS params, this code should scan the
+	 * list of maximum CPU and DMA latencies and select the
+	 * smallest, then set cpu_dma_latency pm_qos_param
+	 * accordingly.
+	 *
+	 * For future Linux PM QOS params, with separate CPU and DMA
+	 * latency params, this code should just set the dma_latency param.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
+{
+	if (!dev || !c || r < 0) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	}
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min clk rate constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add min clk rate constraint: "
+			 "dev %s, rate = %ld Hz\n", dev_name(dev), r);
+
+	/*
+	 * Code in a real implementation should keep track of these
+	 * constraints on the clock, and determine the highest minimum
+	 * clock rate.  It should iterate over each OPP and determine
+	 * whether the OPP will result in a clock rate that would
+	 * satisfy this constraint (and any other PM constraint in effect
+	 * at that time).  Once it finds the lowest-voltage OPP that
+	 * meets those conditions, it should switch to it, or return
+	 * an error if the code is not capable of doing so.
+	 */
+
+	return 0;
+}
+
+/*
+ * DSP Bridge-specific constraints
+ */
+
+const struct omap_opp *omap_pm_dsp_get_opp_table(void)
+{
+	pr_debug("OMAP PM: DSP request for OPP table\n");
+
+	/*
+	 * Return DSP frequency table here:  The final item in the
+	 * array should have .rate = .opp_id = 0.
+	 */
+
+	return NULL;
+}
+
+void omap_pm_dsp_set_min_opp(u8 opp_id)
+{
+	if (opp_id == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
+
+	/*
+	 *
+	 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
+	 * can just test to see which is higher, the CPU's desired OPP
+	 * ID or the DSP's desired OPP ID, and use whichever is
+	 * highest.
+	 *
+	 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
+	 * rate is keyed on MPU speed, not the OPP ID.  So we need to
+	 * map the OPP ID to the MPU speed for use with clk_set_rate()
+	 * if it is higher than the current OPP clock rate.
+	 *
+	 */
+}
+
+
+u8 omap_pm_dsp_get_opp(void)
+{
+	pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
+
+	/*
+	 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
+	 *
+	 * CDP12.14+:
+	 * Call clk_get_rate() on the OPP custom clock, map that to an
+	 * OPP ID using the tables defined in board-*.c/chip-*.c files.
+	 */
+
+	return 0;
+}
+
+/*
+ * CPUFreq-originated constraint
+ *
+ * In the future, this should be handled by custom OPP clocktype
+ * functions.
+ */
+
+struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void)
+{
+	pr_debug("OMAP PM: CPUFreq request for frequency table\n");
+
+	/*
+	 * Return CPUFreq frequency table here: loop over
+	 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
+	 * table
+	 */
+
+	return NULL;
+}
+
+void omap_pm_cpu_set_freq(unsigned long f)
+{
+	if (f == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+		 f);
+
+	/*
+	 * For l-o dev tree, determine whether MPU freq or DSP OPP id
+	 * freq is higher.  Find the OPP ID corresponding to the
+	 * higher frequency.  Call clk_round_rate() and clk_set_rate()
+	 * on the OPP custom clock.
+	 *
+	 * CDP should just be able to set the VDD1 OPP clock rate here.
+	 */
+}
+
+unsigned long omap_pm_cpu_get_freq(void)
+{
+	pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
+
+	/*
+	 * Call clk_get_rate() on the mpu_ck.
+	 */
+
+	return 0;
+}
+
+/**
+ * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been enabled.
+ */
+void omap_pm_enable_off_mode(void)
+{
+	off_mode_enabled = true;
+}
+
+/**
+ * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been disabled.
+ */
+void omap_pm_disable_off_mode(void)
+{
+	off_mode_enabled = false;
+}
+
+/*
+ * Device context loss tracking
+ */
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	u32 count;
+
+	if (WARN_ON(!dev))
+		return 0;
+
+	if (dev->parent == &omap_device_parent) {
+		count = omap_device_get_context_loss_count(pdev);
+	} else {
+		WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context "
+			  "loss counter; device %s should be converted to "
+			  "omap_device", dev_name(dev));
+		if (off_mode_enabled)
+			dummy_context_loss_counter++;
+		count = dummy_context_loss_counter;
+	}
+
+	pr_debug("OMAP PM: context loss count for dev %s = %d\n",
+		 dev_name(dev), count);
+
+	return count;
+}
+
+#else
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	return dummy_context_loss_counter;
+}
+
+#endif
+
+/* Should be called before clk framework init */
+int __init omap_pm_if_early_init(void)
+{
+	return 0;
+}
+
+/* Must be called after clock framework is initialized */
+int __init omap_pm_if_init(void)
+{
+	return 0;
+}
+
+void omap_pm_if_exit(void)
+{
+	/* Deallocate CPUFreq frequency table here */
+}
+
-- 
1.7.2.5


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

* [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (11 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The powerdomains next states are initialized in pwrdms_setup as a
late_initcall. Because the PM QoS devices constraint can be requested
early in the boot sequence, the power domains next states can be
overwritten by pwrdms_setup.

This patch fixes it by initializing the power domains next states
early at boot, so that the constraints can be applied.
Later in the pwrdms_setup function the currently programmed
next states are re-used as next state values.

Applies to OMAP3 and OMAP4.

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/pm34xx.c      |    2 +-
 arch/arm/mach-omap2/pm44xx.c      |    2 +-
 arch/arm/mach-omap2/powerdomain.c |    3 +++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 96a7624..af626ac 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -822,7 +822,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_RET;
+	pwrst->next_state = pwrdm_read_next_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	if (pwrdm_has_hdwr_sar(pwrdm))
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 59a870b..91ede72 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -84,7 +84,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_ON;
+	pwrst->next_state = pwrdm_read_next_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..63c3e7a 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
 
+	/* Early init of the next power state */
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
+
 	pr_debug("powerdomain: registered %s\n", pwrdm->name);
 
 	return 0;
-- 
1.7.2.5

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

* [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (12 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 07/13] OMAP PM: early init of the pwrdms states jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-29  8:08   ` Todd Poynor
  2011-07-29  8:08   ` Todd Poynor
  2011-07-28  8:30 ` [PATCH 08/13] OMAP2+: powerdomain: control power domains next state jean.pihet
                   ` (14 subsequent siblings)
  28 siblings, 2 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

The powerdomains next states are initialized in pwrdms_setup as a
late_initcall. Because the PM QoS devices constraint can be requested
early in the boot sequence, the power domains next states can be
overwritten by pwrdms_setup.

This patch fixes it by initializing the power domains next states
early at boot, so that the constraints can be applied.
Later in the pwrdms_setup function the currently programmed
next states are re-used as next state values.

Applies to OMAP3 and OMAP4.

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/pm34xx.c      |    2 +-
 arch/arm/mach-omap2/pm44xx.c      |    2 +-
 arch/arm/mach-omap2/powerdomain.c |    3 +++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 96a7624..af626ac 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -822,7 +822,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_RET;
+	pwrst->next_state = pwrdm_read_next_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	if (pwrdm_has_hdwr_sar(pwrdm))
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 59a870b..91ede72 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -84,7 +84,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_ON;
+	pwrst->next_state = pwrdm_read_next_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..63c3e7a 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
 
+	/* Early init of the next power state */
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
+
 	pr_debug("powerdomain: registered %s\n", pwrdm->name);
 
 	return 0;
-- 
1.7.2.5


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

* [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (14 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 08/13] OMAP2+: powerdomain: control power domains next state jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 09/13] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

When a PM QoS device latency constraint is requested or removed the
PM QoS layer notifies the underlying layer with the updated aggregated
constraint value. The constraint is stored in the powerdomain constraints
list and then applied to the corresponding power domain.
The power domains get the next power state programmed directly in the
registers via pwrdm_wakeuplat_update_pwrst.

Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using
wake-up latency constraints on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/powerdomain.c |  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 63c3e7a..c0f48ab 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -17,8 +17,10 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/pm_qos.h>
 #include <trace/events/power.h>
 
 #include "cm2xxx_3xxx.h"
@@ -104,6 +106,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;
@@ -194,6 +202,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 */
 
 /**
@@ -933,6 +1012,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_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.2.5

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

* [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (13 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-29  7:59   ` Todd Poynor
  2011-07-29  7:59   ` Todd Poynor
  2011-07-28  8:30 ` jean.pihet
                   ` (13 subsequent siblings)
  28 siblings, 2 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

When a PM QoS device latency constraint is requested or removed the
PM QoS layer notifies the underlying layer with the updated aggregated
constraint value. The constraint is stored in the powerdomain constraints
list and then applied to the corresponding power domain.
The power domains get the next power state programmed directly in the
registers via pwrdm_wakeuplat_update_pwrst.

Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using
wake-up latency constraints on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/powerdomain.c |  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 63c3e7a..c0f48ab 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -17,8 +17,10 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/pm_qos.h>
 #include <trace/events/power.h>
 
 #include "cm2xxx_3xxx.h"
@@ -104,6 +106,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;
@@ -194,6 +202,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 */
 
 /**
@@ -933,6 +1012,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_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.2.5


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

* [PATCH 09/13] OMAP3: powerdomain data: add wake-up latency figures
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (15 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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.2.5

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

* [PATCH 09/13] OMAP3: powerdomain data: add wake-up latency figures
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (16 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 09/13] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 10/13] OMAP4: " jean.pihet
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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.2.5


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

* [PATCH 10/13] OMAP4: powerdomain data: add wake-up latency figures
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (17 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8:30 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 |   84 +++++++++++++++++++++++++++
 1 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index 247e794..c3f8dd4 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,
+	},
 };
 
 /*
-- 
1.7.2.5

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

* [PATCH 10/13] OMAP4: powerdomain data: add wake-up latency figures
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (18 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 10/13] OMAP4: " jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 11/13] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8:30 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 |   84 +++++++++++++++++++++++++++
 1 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index 247e794..c3f8dd4 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,
+	},
 };
 
 /*
-- 
1.7.2.5


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

* [PATCH 11/13] OMAP2+: omap_hwmod: manage the wake-up latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (20 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 11/13] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 12/13] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Hwmod is queried from the OMAP_PM layer to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.

Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 +++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    2 ++
 2 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..c6b1cc9 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -143,6 +143,7 @@
 #include "powerdomain.h"
 #include <plat/clock.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 #include <plat/prcm.h>
 
 #include "cm2xxx_3xxx.h"
@@ -2618,11 +2619,34 @@ ohsps_unlock:
 	return ret;
 }
 
+/*
+ * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
+ *
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Returns 0 upon success.
+ */
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
+				       void *cookie, long min_latency)
+{
+	struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+	if (!pwrdm) {
+		pr_err("%s: Error: could not find powerdomain "
+		       "for %s\n", __func__, oh->name);
+		return -EINVAL;
+	}
+
+	return pwrdm_set_wkup_lat_constraint(pwrdm, cookie, min_latency);
+}
+
 /**
  * omap_hwmod_get_context_loss_count - get lost context count
  * @oh: struct omap_hwmod *
  *
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
  * count for this device.
  *
  * Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 0e329ca..75e0e7a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -603,6 +603,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
 				 void *user);
 
 int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh, void *cookie,
+				       long min_latency);
 u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
-- 
1.7.2.5

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

* [PATCH 11/13] OMAP2+: omap_hwmod: manage the wake-up latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (19 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

Hwmod is queried from the OMAP_PM layer to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.

Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 +++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    2 ++
 2 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..c6b1cc9 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -143,6 +143,7 @@
 #include "powerdomain.h"
 #include <plat/clock.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 #include <plat/prcm.h>
 
 #include "cm2xxx_3xxx.h"
@@ -2618,11 +2619,34 @@ ohsps_unlock:
 	return ret;
 }
 
+/*
+ * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
+ *
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Returns 0 upon success.
+ */
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
+				       void *cookie, long min_latency)
+{
+	struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+	if (!pwrdm) {
+		pr_err("%s: Error: could not find powerdomain "
+		       "for %s\n", __func__, oh->name);
+		return -EINVAL;
+	}
+
+	return pwrdm_set_wkup_lat_constraint(pwrdm, cookie, min_latency);
+}
+
 /**
  * omap_hwmod_get_context_loss_count - get lost context count
  * @oh: struct omap_hwmod *
  *
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
  * count for this device.
  *
  * Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 0e329ca..75e0e7a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -603,6 +603,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
 				 void *user);
 
 int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh, void *cookie,
+				       long min_latency);
 u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
-- 
1.7.2.5


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

* [PATCH 12/13] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (21 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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/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 ---------------
 3 files changed, 75 insertions(+), 311 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 0840df8..d276082 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -62,136 +62,8 @@ void omap_pm_if_exit(void);
  * Device-driver-originated constraints (via board-*.c files, platform_data)
  */
 
-
-/**
- * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency
- * @dev: struct device * requesting the constraint
- * @t: maximum MPU wakeup latency in microseconds
- *
- * Request that the maximum interrupt latency for the MPU to be no
- * greater than @t microseconds. "Interrupt latency" in this case is
- * defined as the elapsed time from the occurrence of a hardware or
- * timer interrupt to the time when the device driver's interrupt
- * service routine has been entered by the MPU.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the MPU powerdomain into, and
- * possibly the CORE powerdomain as well, since interrupt handling
- * code currently runs from SDRAM.  Advanced PM or board*.c code may
- * also configure interrupt controller priorities, OCP bus priorities,
- * CPU speed(s), etc.
- *
- * This function will not affect device wakeup latency, e.g., time
- * elapsed from when a device driver enables a hardware device with
- * clk_enable(), to when the device is ready for register access or
- * other use.  To control this device wakeup latency, use
- * omap_pm_set_max_dev_wakeup_lat()
- *
- * Multiple calls to omap_pm_set_max_mpu_wakeup_lat() will replace the
- * previous t value.  To remove the latency target for the MPU, call
- * with t = -1.
- *
- * XXX This constraint will be deprecated soon in favor of the more
- * general omap_pm_set_max_dev_wakeup_lat()
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
-
-
-/**
- * omap_pm_set_min_bus_tput - set minimum bus throughput needed by device
- * @dev: struct device * requesting the constraint
- * @tbus_id: interconnect to operate on (OCP_{INITIATOR,TARGET}_AGENT)
- * @r: minimum throughput (in KiB/s)
- *
- * Request that the minimum data throughput on the OCP interconnect
- * attached to device @dev interconnect agent @tbus_id be no less
- * than @r KiB/s.
- *
- * It is expected that the OMAP PM or bus code will use this
- * information to set the interconnect clock to run at the lowest
- * possible speed that satisfies all current system users.  The PM or
- * bus code will adjust the estimate based on its model of the bus, so
- * device driver authors should attempt to specify an accurate
- * quantity for their device use case, and let the PM or bus code
- * overestimate the numbers as necessary to handle request/response
- * latency, other competing users on the system, etc.  On OMAP2/3, if
- * a driver requests a minimum L4 interconnect speed constraint, the
- * code will also need to add an minimum L3 interconnect speed
- * constraint,
- *
- * Multiple calls to omap_pm_set_min_bus_tput() will replace the
- * previous rate value for this device.  To remove the interconnect
- * throughput restriction for this device, call with r = 0.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
 int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r);
 
-
-/**
- * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
- * @req_dev: struct device * requesting the constraint, or NULL if none
- * @dev: struct device * to set the constraint one
- * @t: maximum device wakeup latency in microseconds
- *
- * Request that the maximum amount of time necessary for a device @dev
- * to become accessible after its clocks are enabled should be no
- * greater than @t microseconds.  Specifically, this represents the
- * time from when a device driver enables device clocks with
- * clk_enable(), to when the register reads and writes on the device
- * will succeed.  This function should be called before clk_disable()
- * is called, since the power state transition decision may be made
- * during clk_disable().
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the powerdomain enclosing this
- * device into.
- *
- * Multiple calls to omap_pm_set_max_dev_wakeup_lat() will replace the
- * previous wakeup latency values for this device.  To remove the
- * wakeup latency restriction for this device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
-				   long t);
-
-
-/**
- * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency
- * @dev: struct device *
- * @t: maximum DMA transfer start latency in microseconds
- *
- * Request that the maximum system DMA transfer start latency for this
- * device 'dev' should be no greater than 't' microseconds.  "DMA
- * transfer start latency" here is defined as the elapsed time from
- * when a device (e.g., McBSP) requests that a system DMA transfer
- * start or continue, to the time at which data starts to flow into
- * that device from the system DMA controller.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the CORE powerdomain into.
- *
- * Since system DMA transfers may not involve the MPU, this function
- * will not affect MPU wakeup latency.  Use set_max_cpu_lat() to do
- * so.  Similarly, this function will not affect device wakeup latency
- * -- use set_max_dev_wakeup_lat() to affect that.
- *
- * Multiple calls to set_max_sdma_lat() will replace the previous t
- * value for this device.  To remove the maximum DMA latency for this
- * device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_sdma_lat(struct device *dev, long t);
-
-
 /**
  * omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
  * @dev: struct device * requesting the constraint
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
index c8b4e4c..5e63b04 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.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 *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->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_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.2.5

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

* [PATCH 12/13] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (22 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 12/13] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` [PATCH 13/13] OMAP2+: cpuidle only influences the MPU state jean.pihet
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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/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 ---------------
 3 files changed, 75 insertions(+), 311 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 0840df8..d276082 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -62,136 +62,8 @@ void omap_pm_if_exit(void);
  * Device-driver-originated constraints (via board-*.c files, platform_data)
  */
 
-
-/**
- * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency
- * @dev: struct device * requesting the constraint
- * @t: maximum MPU wakeup latency in microseconds
- *
- * Request that the maximum interrupt latency for the MPU to be no
- * greater than @t microseconds. "Interrupt latency" in this case is
- * defined as the elapsed time from the occurrence of a hardware or
- * timer interrupt to the time when the device driver's interrupt
- * service routine has been entered by the MPU.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the MPU powerdomain into, and
- * possibly the CORE powerdomain as well, since interrupt handling
- * code currently runs from SDRAM.  Advanced PM or board*.c code may
- * also configure interrupt controller priorities, OCP bus priorities,
- * CPU speed(s), etc.
- *
- * This function will not affect device wakeup latency, e.g., time
- * elapsed from when a device driver enables a hardware device with
- * clk_enable(), to when the device is ready for register access or
- * other use.  To control this device wakeup latency, use
- * omap_pm_set_max_dev_wakeup_lat()
- *
- * Multiple calls to omap_pm_set_max_mpu_wakeup_lat() will replace the
- * previous t value.  To remove the latency target for the MPU, call
- * with t = -1.
- *
- * XXX This constraint will be deprecated soon in favor of the more
- * general omap_pm_set_max_dev_wakeup_lat()
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
-
-
-/**
- * omap_pm_set_min_bus_tput - set minimum bus throughput needed by device
- * @dev: struct device * requesting the constraint
- * @tbus_id: interconnect to operate on (OCP_{INITIATOR,TARGET}_AGENT)
- * @r: minimum throughput (in KiB/s)
- *
- * Request that the minimum data throughput on the OCP interconnect
- * attached to device @dev interconnect agent @tbus_id be no less
- * than @r KiB/s.
- *
- * It is expected that the OMAP PM or bus code will use this
- * information to set the interconnect clock to run at the lowest
- * possible speed that satisfies all current system users.  The PM or
- * bus code will adjust the estimate based on its model of the bus, so
- * device driver authors should attempt to specify an accurate
- * quantity for their device use case, and let the PM or bus code
- * overestimate the numbers as necessary to handle request/response
- * latency, other competing users on the system, etc.  On OMAP2/3, if
- * a driver requests a minimum L4 interconnect speed constraint, the
- * code will also need to add an minimum L3 interconnect speed
- * constraint,
- *
- * Multiple calls to omap_pm_set_min_bus_tput() will replace the
- * previous rate value for this device.  To remove the interconnect
- * throughput restriction for this device, call with r = 0.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
 int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r);
 
-
-/**
- * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
- * @req_dev: struct device * requesting the constraint, or NULL if none
- * @dev: struct device * to set the constraint one
- * @t: maximum device wakeup latency in microseconds
- *
- * Request that the maximum amount of time necessary for a device @dev
- * to become accessible after its clocks are enabled should be no
- * greater than @t microseconds.  Specifically, this represents the
- * time from when a device driver enables device clocks with
- * clk_enable(), to when the register reads and writes on the device
- * will succeed.  This function should be called before clk_disable()
- * is called, since the power state transition decision may be made
- * during clk_disable().
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the powerdomain enclosing this
- * device into.
- *
- * Multiple calls to omap_pm_set_max_dev_wakeup_lat() will replace the
- * previous wakeup latency values for this device.  To remove the
- * wakeup latency restriction for this device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
-				   long t);
-
-
-/**
- * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency
- * @dev: struct device *
- * @t: maximum DMA transfer start latency in microseconds
- *
- * Request that the maximum system DMA transfer start latency for this
- * device 'dev' should be no greater than 't' microseconds.  "DMA
- * transfer start latency" here is defined as the elapsed time from
- * when a device (e.g., McBSP) requests that a system DMA transfer
- * start or continue, to the time at which data starts to flow into
- * that device from the system DMA controller.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the CORE powerdomain into.
- *
- * Since system DMA transfers may not involve the MPU, this function
- * will not affect MPU wakeup latency.  Use set_max_cpu_lat() to do
- * so.  Similarly, this function will not affect device wakeup latency
- * -- use set_max_dev_wakeup_lat() to affect that.
- *
- * Multiple calls to set_max_sdma_lat() will replace the previous t
- * value for this device.  To remove the maximum DMA latency for this
- * device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_sdma_lat(struct device *dev, long t);
-
-
 /**
  * omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
  * @dev: struct device * requesting the constraint
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
index c8b4e4c..5e63b04 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.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 *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->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_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.2.5


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

* [PATCH 13/13] OMAP2+: cpuidle only influences the MPU state
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (24 preceding siblings ...)
  2011-07-28  8:30 ` [PATCH 13/13] OMAP2+: cpuidle only influences the MPU state jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28 13:14 ` [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class mark gross
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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_LATENCY class of the PM QoS framework,
via the devices wake-up latency constraints.

Note: the exit_latency and target_residency figures of the MPU
include the MPU itself and the peripherals needed for the MPU to
execute instructions (e.g. main memory, caches, IRQ controller,
MMU etc). Some of those peripherals can belong to other power domains
than the MPU subsystem and so the corresponding latencies must be
included in this figure.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/cpuidle34xx.c |   42 +++++++++++-------------------------
 arch/arm/mach-omap2/pm.h          |   17 +++++++++++++-
 2 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..b43d1d2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -37,26 +37,26 @@
 #ifdef CONFIG_CPU_IDLE
 
 /*
- * The latencies/thresholds for various C states have
+ * The MPU latencies/thresholds for various C states have
  * to be configured from the respective board files.
  * These are some default values (which might not provide
  * the best power savings) used on boards which do not
  * pass these details from the board file.
  */
 static struct cpuidle_params cpuidle_params_table[] = {
-	/* C1 */
+	/* C1 . MPU WFI + Core active */
 	{2 + 2, 5, 1},
-	/* C2 */
+	/* C2 . MPU WFI + Core inactive */
 	{10 + 10, 30, 1},
-	/* C3 */
+	/* C3 . MPU CSWR + Core inactive */
 	{50 + 50, 300, 1},
-	/* C4 */
+	/* C4 . MPU OFF + Core inactive */
 	{1500 + 1800, 4000, 1},
-	/* C5 */
+	/* C5 . MPU RET + Core RET */
 	{2500 + 7500, 12000, 1},
-	/* C6 */
+	/* C6 . MPU OFF + Core RET */
 	{3000 + 8500, 15000, 1},
-	/* C7 */
+	/* C7 . MPU OFF + Core OFF */
 	{10000 + 30000, 300000, 1},
 };
 #define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
@@ -64,7 +64,6 @@ static struct cpuidle_params cpuidle_params_table[] = {
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
 	u32 mpu_state;
-	u32 core_state;
 	u8 valid;
 };
 struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
@@ -98,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 {
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+	u32 mpu_state = cx->mpu_state;
 
 	/* Used to keep track of the total time in idle */
 	getnstimeofday(&ts_preidle);
@@ -107,7 +106,6 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 	local_fiq_disable();
 
 	pwrdm_set_next_pwrst(mpu_pd, mpu_state);
-	pwrdm_set_next_pwrst(core_pd, core_state);
 
 	if (omap_irq_pending() || need_resched())
 		goto return_sleep_time;
@@ -156,6 +154,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
+	u32 core_next_state = pwrdm_read_next_pwrst(core_pd);
 
 	if (enable_off_mode) {
 		mpu_deepest_state = PWRDM_POWER_OFF;
@@ -171,7 +170,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 	/* Check if current state is valid */
 	if ((cx->valid) &&
 	    (cx->mpu_state >= mpu_deepest_state) &&
-	    (cx->core_state >= core_deepest_state)) {
+	    (core_next_state >= core_deepest_state)) {
 		return curr;
 	} else {
 		int idx = OMAP3_NUM_STATES - 1;
@@ -196,7 +195,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 			cx = cpuidle_get_statedata(&dev->states[idx]);
 			if ((cx->valid) &&
 			    (cx->mpu_state >= mpu_deepest_state) &&
-			    (cx->core_state >= core_deepest_state)) {
+			    (core_next_state >= core_deepest_state)) {
 				next = &dev->states[idx];
 				break;
 			}
@@ -242,19 +241,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	}
 
 	/*
-	 * FIXME: we currently manage device-specific idle states
-	 *        for PER and CORE in combination with CPU-specific
-	 *        idle states.  This is wrong, and device-specific
-	 *        idle management needs to be separated out into
-	 *        its own code.
-	 */
-
-	/*
 	 * Prevent PER off if CORE is not in retention or off as this
 	 * would disable PER wakeups completely.
 	 */
 	cx = cpuidle_get_statedata(state);
-	core_next_state = cx->core_state;
+	core_next_state = pwrdm_read_next_pwrst(core_pd);
 	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
 	if ((per_next_state == PWRDM_POWER_OFF) &&
 	    (core_next_state > PWRDM_POWER_RET))
@@ -346,32 +337,26 @@ int __init omap3_idle_init(void)
 	dev->safe_state = &dev->states[0];
 	cx->valid = 1;	/* C1 is always valid */
 	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C2 . MPU WFI + Core inactive */
 	cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
 	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C3 . MPU CSWR + Core inactive */
 	cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
 	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C4 . MPU OFF + Core inactive */
 	cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C5 . MPU RET + Core RET */
 	cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
 	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_RET;
 
 	/* C6 . MPU OFF + Core RET */
 	cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_RET;
 
 	/* C7 . MPU OFF + Core OFF */
 	cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
@@ -386,7 +371,6 @@ int __init omap3_idle_init(void)
 			__func__);
 	}
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_OFF;
 
 	dev->state_count = OMAP3_NUM_STATES;
 	if (cpuidle_register_device(dev)) {
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index babac19..38327dc 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -43,9 +43,22 @@ static inline int omap4_opp_init(void)
  * omap3_pm_init_cpuidle
  */
 struct cpuidle_params {
-	u32 exit_latency;	/* exit_latency = sleep + wake-up latencies */
+	/*
+	 * exit_latency = sleep + wake-up latencies of the MPU,
+	 * which include the MPU itself and the peripherals needed
+	 * for the MPU to execute instructions (e.g. main memory,
+	 * caches, IRQ controller, MMU etc). Some of those peripherals
+	 * can belong to other power domains than the MPU subsystem and so
+	 * the corresponding latencies must be included in this figure.
+	 */
+	u32 exit_latency;
+	/*
+	 * target_residency: required amount of time in the C state
+	 * to break even on energy cost
+	 */
 	u32 target_residency;
-	u8 valid;		/* validates the C-state */
+	/* validates the C-state on the given board */
+	u8 valid;
 };
 
 #if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
-- 
1.7.2.5

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

* [PATCH 13/13] OMAP2+: cpuidle only influences the MPU state
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (23 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28  8:30 ` jean.pihet
  2011-07-28  8:30 ` jean.pihet
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 78+ messages in thread
From: jean.pihet @ 2011-07-28  8: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>

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_LATENCY class of the PM QoS framework,
via the devices wake-up latency constraints.

Note: the exit_latency and target_residency figures of the MPU
include the MPU itself and the peripherals needed for the MPU to
execute instructions (e.g. main memory, caches, IRQ controller,
MMU etc). Some of those peripherals can belong to other power domains
than the MPU subsystem and so the corresponding latencies must be
included in this figure.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/cpuidle34xx.c |   42 +++++++++++-------------------------
 arch/arm/mach-omap2/pm.h          |   17 +++++++++++++-
 2 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..b43d1d2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -37,26 +37,26 @@
 #ifdef CONFIG_CPU_IDLE
 
 /*
- * The latencies/thresholds for various C states have
+ * The MPU latencies/thresholds for various C states have
  * to be configured from the respective board files.
  * These are some default values (which might not provide
  * the best power savings) used on boards which do not
  * pass these details from the board file.
  */
 static struct cpuidle_params cpuidle_params_table[] = {
-	/* C1 */
+	/* C1 . MPU WFI + Core active */
 	{2 + 2, 5, 1},
-	/* C2 */
+	/* C2 . MPU WFI + Core inactive */
 	{10 + 10, 30, 1},
-	/* C3 */
+	/* C3 . MPU CSWR + Core inactive */
 	{50 + 50, 300, 1},
-	/* C4 */
+	/* C4 . MPU OFF + Core inactive */
 	{1500 + 1800, 4000, 1},
-	/* C5 */
+	/* C5 . MPU RET + Core RET */
 	{2500 + 7500, 12000, 1},
-	/* C6 */
+	/* C6 . MPU OFF + Core RET */
 	{3000 + 8500, 15000, 1},
-	/* C7 */
+	/* C7 . MPU OFF + Core OFF */
 	{10000 + 30000, 300000, 1},
 };
 #define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
@@ -64,7 +64,6 @@ static struct cpuidle_params cpuidle_params_table[] = {
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
 	u32 mpu_state;
-	u32 core_state;
 	u8 valid;
 };
 struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
@@ -98,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 {
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+	u32 mpu_state = cx->mpu_state;
 
 	/* Used to keep track of the total time in idle */
 	getnstimeofday(&ts_preidle);
@@ -107,7 +106,6 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
 	local_fiq_disable();
 
 	pwrdm_set_next_pwrst(mpu_pd, mpu_state);
-	pwrdm_set_next_pwrst(core_pd, core_state);
 
 	if (omap_irq_pending() || need_resched())
 		goto return_sleep_time;
@@ -156,6 +154,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 	struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
 	u32 mpu_deepest_state = PWRDM_POWER_RET;
 	u32 core_deepest_state = PWRDM_POWER_RET;
+	u32 core_next_state = pwrdm_read_next_pwrst(core_pd);
 
 	if (enable_off_mode) {
 		mpu_deepest_state = PWRDM_POWER_OFF;
@@ -171,7 +170,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 	/* Check if current state is valid */
 	if ((cx->valid) &&
 	    (cx->mpu_state >= mpu_deepest_state) &&
-	    (cx->core_state >= core_deepest_state)) {
+	    (core_next_state >= core_deepest_state)) {
 		return curr;
 	} else {
 		int idx = OMAP3_NUM_STATES - 1;
@@ -196,7 +195,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
 			cx = cpuidle_get_statedata(&dev->states[idx]);
 			if ((cx->valid) &&
 			    (cx->mpu_state >= mpu_deepest_state) &&
-			    (cx->core_state >= core_deepest_state)) {
+			    (core_next_state >= core_deepest_state)) {
 				next = &dev->states[idx];
 				break;
 			}
@@ -242,19 +241,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	}
 
 	/*
-	 * FIXME: we currently manage device-specific idle states
-	 *        for PER and CORE in combination with CPU-specific
-	 *        idle states.  This is wrong, and device-specific
-	 *        idle management needs to be separated out into
-	 *        its own code.
-	 */
-
-	/*
 	 * Prevent PER off if CORE is not in retention or off as this
 	 * would disable PER wakeups completely.
 	 */
 	cx = cpuidle_get_statedata(state);
-	core_next_state = cx->core_state;
+	core_next_state = pwrdm_read_next_pwrst(core_pd);
 	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
 	if ((per_next_state == PWRDM_POWER_OFF) &&
 	    (core_next_state > PWRDM_POWER_RET))
@@ -346,32 +337,26 @@ int __init omap3_idle_init(void)
 	dev->safe_state = &dev->states[0];
 	cx->valid = 1;	/* C1 is always valid */
 	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C2 . MPU WFI + Core inactive */
 	cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
 	cx->mpu_state = PWRDM_POWER_ON;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C3 . MPU CSWR + Core inactive */
 	cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
 	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C4 . MPU OFF + Core inactive */
 	cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_ON;
 
 	/* C5 . MPU RET + Core RET */
 	cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
 	cx->mpu_state = PWRDM_POWER_RET;
-	cx->core_state = PWRDM_POWER_RET;
 
 	/* C6 . MPU OFF + Core RET */
 	cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_RET;
 
 	/* C7 . MPU OFF + Core OFF */
 	cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
@@ -386,7 +371,6 @@ int __init omap3_idle_init(void)
 			__func__);
 	}
 	cx->mpu_state = PWRDM_POWER_OFF;
-	cx->core_state = PWRDM_POWER_OFF;
 
 	dev->state_count = OMAP3_NUM_STATES;
 	if (cpuidle_register_device(dev)) {
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index babac19..38327dc 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -43,9 +43,22 @@ static inline int omap4_opp_init(void)
  * omap3_pm_init_cpuidle
  */
 struct cpuidle_params {
-	u32 exit_latency;	/* exit_latency = sleep + wake-up latencies */
+	/*
+	 * exit_latency = sleep + wake-up latencies of the MPU,
+	 * which include the MPU itself and the peripherals needed
+	 * for the MPU to execute instructions (e.g. main memory,
+	 * caches, IRQ controller, MMU etc). Some of those peripherals
+	 * can belong to other power domains than the MPU subsystem and so
+	 * the corresponding latencies must be included in this figure.
+	 */
+	u32 exit_latency;
+	/*
+	 * target_residency: required amount of time in the C state
+	 * to break even on energy cost
+	 */
 	u32 target_residency;
-	u8 valid;		/* validates the C-state */
+	/* validates the C-state on the given board */
+	u8 valid;
 };
 
 #if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
-- 
1.7.2.5


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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (25 preceding siblings ...)
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-28 13:14 ` mark gross
  2011-07-29  8:37   ` Jean Pihet
  2011-07-29  8:37   ` Jean Pihet
  2011-07-29 21:25 ` Rafael J. Wysocki
  2011-07-29 21:25 ` Rafael J. Wysocki
  28 siblings, 2 replies; 78+ messages in thread
From: mark gross @ 2011-07-28 13:14 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thu, Jul 28, 2011 at 10:30:07AM +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.
> 
> High level implementation:
> 
> 1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_LATENCY).
> . Define a pm_qos_constraints struct for the storage of the constraints list
> and associated values (target_value, default_value, type ...).
> . Update the pm_qos_object struct with the information related to a PM QoS
> class: ptr to constraints list, notifer ptr, name ...
> . Each PM QoS class statically declare objects for pm_qos_object and
> pm_qos_constraints. The only exception is the devices constraints, cf. below.
> . The device constraints class is statically declaring a pm_qos_object. The
> pm_qos_constraints are per-device and so are embedded into the device struct.
> 
> The new class is available from kernel drivers and shall be made available
> to user space through a per-device sysfs entry. User space API to come as a 
> subsequent patch.
> 
> 2. Added a notification of device insertion/removal from the device PM framework
> to PM QoS.
> This allows to init/de-init the per-device constraints list upon device insertion
> and removal.
> RFC state for comments and review, lightly tested
> 
> 3. Make the pm_qos_add_request API more generic by using a
> struct pm_qos_parameters parameter. This allows easy extension in the future.
> 
> 4. Upon a change of the aggregated constraint value in the PM_QOS_DEV_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. 5 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.
> 
> 5. 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_LATENCY class of the PM QoS framework, via the device
> wake-up latency constraints callback to the OMAP_PM_CONSTRAINTS framework.
> 
> 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 those figures.
> 
> 6. Update the pm_qos_add_request callers to the generic API
> 
> 7. Misc fixes to improve code readability:
> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
I picked the name for the file as pm_qos_params over pm_qos because I
wanted to make it implicitly clear that this was not an full QOS
implementation.  True QOS carries expectations similar to real time and
as the infrastructure is closer to "good intentioned" than even "best
effort" and offers no notification when the QOS request is not able to
be met and really doesn't implement a true QOS at all, (it just provides
the parameter interface for part of one its missing the notification
interface when the service level is not met and I think a few other
things.) So I wanted to have it named a bit different from just pm_qos.

This said I'm not supper attached to the naming of the modules.  If
folks want to change it I wouldn't complain (too much anyway;).

--mark
PS I'll look at the rest of the patches tomorrow, this time for real as
I'm about to have more free time to focus on non-work stuff :)
FWIW this write up sounds interesting.


> . rename of fields names (request, list, constraints, class),
> . simplification of the in-kernel PM QoS API implementation. The main logic part
> is now implemented in the update_target function.
> 
> Questions:
> 1. per-device user-space API: since sysfs does not provide open/close
> callbacks it is not possible to support multiple and simultaneous users of
> the per-device sysfs entry. A user-space constraints aggregation application is
> needed in case of multiple constraints for a device. Is this the way to go?
> 
> On-going developments, patches in preparation:
> 1. add a user-space API for the devices constratins PM QoS, using a sysfs entry
>    per device
> 2. write Documentation for the new PM QoS class, once the RFC is agreed on
> 3. validate the constraints framework on OMAP4 HW (done on OMAP3)
> 4. 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-rc7). Compile
> tested using OMAP and x86 generic defconfigs.
> Lightly tested on OMAP3 Beagleboard (ES2.x).
> 
> 
> Changelog:
> 
> v3:
> . Complete PM QoS re-design after the comments on MLs
> . Patch set split up for improved readability and easier maintenance
> 
> v2:
> . Rework after comments on the mailing lists
> . Added a notification of device insertion/removal from the device PM framework
> . Validated on OMAP3 HW
> 
> v1:
> . Initial implementation
> 
> 
> Jean Pihet (12):
>   PM: QoS: rename pm_qos_params files to pm_qos
>   PM: add a per-device wake-up latency constraints plist
>   PM: QoS: extend the in-kernel API with per-device latency constraints
>   PM: QoS: implement the per-device latency constraints
>   PM: QoS: support the dynamic insertion and removal of devices
>   OMAP PM: create a PM layer plugin for per-device constraints
>   OMAP PM: early init of the pwrdms states
>   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-msm/clock.c                    |    2 +-
>  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/pm34xx.c                 |    2 +-
>  arch/arm/mach-omap2/pm44xx.c                 |    2 +-
>  arch/arm/mach-omap2/powerdomain.c            |  190 +++++++++
>  arch/arm/mach-omap2/powerdomain.h            |   33 ++-
>  arch/arm/mach-omap2/powerdomains3xxx_data.c  |   77 ++++
>  arch/arm/mach-omap2/powerdomains44xx_data.c  |   84 ++++
>  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/acpi/processor_idle.c                |    2 +-
>  drivers/base/power/main.c                    |    4 +
>  drivers/cpuidle/cpuidle.c                    |    2 +-
>  drivers/cpuidle/governors/ladder.c           |    2 +-
>  drivers/cpuidle/governors/menu.c             |    2 +-
>  drivers/i2c/busses/i2c-omap.c                |   35 +-
>  drivers/media/video/via-camera.c             |    9 +-
>  drivers/net/e1000e/netdev.c                  |   11 +-
>  drivers/net/wireless/ipw2x00/ipw2100.c       |   10 +-
>  drivers/staging/msm/lcdc.c                   |    2 +-
>  drivers/staging/msm/tvenc.c                  |    2 +-
>  include/linux/netdevice.h                    |    4 +-
>  include/linux/pm.h                           |    4 +
>  include/linux/pm_qos.h                       |   68 ++++
>  include/linux/pm_qos_params.h                |   38 --
>  include/sound/pcm.h                          |    4 +-
>  kernel/Makefile                              |    2 +-
>  kernel/pm_qos.c                              |  557 ++++++++++++++++++++++++++
>  kernel/pm_qos_params.c                       |  481 ----------------------
>  net/mac80211/main.c                          |    2 +-
>  net/mac80211/mlme.c                          |    2 +-
>  net/mac80211/scan.c                          |    2 +-
>  sound/core/pcm_native.c                      |   10 +-
>  40 files changed, 1487 insertions(+), 834 deletions(-)
>  create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c
>  create mode 100644 include/linux/pm_qos.h
>  delete mode 100644 include/linux/pm_qos_params.h
>  create mode 100644 kernel/pm_qos.c
>  delete mode 100644 kernel/pm_qos_params.c
> 
> -- 
> 1.7.2.5
> 

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-28  8:30 ` [PATCH 08/13] OMAP2+: powerdomain: control power domains next state jean.pihet
@ 2011-07-29  7:59   ` Todd Poynor
  2011-07-29  7:59   ` Todd Poynor
  1 sibling, 0 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29  7:59 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thu, Jul 28, 2011 at 10:30:15AM +0200, jean.pihet@newoldbits.com wrote:
...
> +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_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;

All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
free_new_user = 1.  (Or maybe change the logic to check user !=
new_user and free new_user if so.)

> +	}
> +
> +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);

Need:
        kfree(new_user);

> +	return ret;
> +}


Todd

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-28  8:30 ` [PATCH 08/13] OMAP2+: powerdomain: control power domains next state jean.pihet
  2011-07-29  7:59   ` Todd Poynor
@ 2011-07-29  7:59   ` Todd Poynor
  2011-07-29  8:47     ` Jean Pihet
  2011-07-29  8:47     ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29  7:59 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet

On Thu, Jul 28, 2011 at 10:30:15AM +0200, jean.pihet@newoldbits.com wrote:
...
> +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_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;

All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
free_new_user = 1.  (Or maybe change the logic to check user !=
new_user and free new_user if so.)

> +	}
> +
> +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);

Need:
        kfree(new_user);

> +	return ret;
> +}


Todd

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-28  8:30 ` jean.pihet
  2011-07-29  8:08   ` Todd Poynor
@ 2011-07-29  8:08   ` Todd Poynor
  1 sibling, 0 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29  8:08 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> The powerdomains next states are initialized in pwrdms_setup as a
> late_initcall. Because the PM QoS devices constraint can be requested
> early in the boot sequence, the power domains next states can be
> overwritten by pwrdms_setup.
> 
> This patch fixes it by initializing the power domains next states
> early at boot, so that the constraints can be applied.
> Later in the pwrdms_setup function the currently programmed
> next states are re-used as next state values.
> 
> Applies to OMAP3 and OMAP4.
> 
> 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>
> ---
...
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index 9af0847..63c3e7a 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>  	pwrdm->state = pwrdm_read_pwrst(pwrdm);
>  	pwrdm->state_counter[pwrdm->state] = 1;
>  
> +	/* Early init of the next power state */
> +	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
> +

Wanted to check that it's OK to initialize the next state of a power
domain to RETENTION early in the boot sequence.  I believe patches
have been previously discussed that set the state to ON to ensure the
domain doesn't go to a lower state, and possibly lose context, before
the PM subsystem is setup to handle it?  Not sure, thought maybe worth
a doublecheck.


Todd

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-29  8:08   ` Todd Poynor
  2011-07-29  8:50     ` Jean Pihet
  2011-07-29  8:50     ` Jean Pihet
  2011-07-29  8:08   ` Todd Poynor
  1 sibling, 2 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29  8:08 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet, rnayak

On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> The powerdomains next states are initialized in pwrdms_setup as a
> late_initcall. Because the PM QoS devices constraint can be requested
> early in the boot sequence, the power domains next states can be
> overwritten by pwrdms_setup.
> 
> This patch fixes it by initializing the power domains next states
> early at boot, so that the constraints can be applied.
> Later in the pwrdms_setup function the currently programmed
> next states are re-used as next state values.
> 
> Applies to OMAP3 and OMAP4.
> 
> 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>
> ---
...
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index 9af0847..63c3e7a 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>  	pwrdm->state = pwrdm_read_pwrst(pwrdm);
>  	pwrdm->state_counter[pwrdm->state] = 1;
>  
> +	/* Early init of the next power state */
> +	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
> +

Wanted to check that it's OK to initialize the next state of a power
domain to RETENTION early in the boot sequence.  I believe patches
have been previously discussed that set the state to ON to ensure the
domain doesn't go to a lower state, and possibly lose context, before
the PM subsystem is setup to handle it?  Not sure, thought maybe worth
a doublecheck.


Todd


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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-28 13:14 ` [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class mark gross
@ 2011-07-29  8:37   ` Jean Pihet
  2011-07-29  8:37   ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:37 UTC (permalink / raw)
  To: markgross; +Cc: broonie, Linux PM mailing list, linux-omap, Jean Pihet

Mark,

On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> On Thu, Jul 28, 2011 at 10:30:07AM +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.
>>
>> High level implementation:
>>
...

>> 7. Misc fixes to improve code readability:
>> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> I picked the name for the file as pm_qos_params over pm_qos because I
> wanted to make it implicitly clear that this was not an full QOS
> implementation.  True QOS carries expectations similar to real time and
> as the infrastructure is closer to "good intentioned" than even "best
> effort" and offers no notification when the QOS request is not able to
> be met and really doesn't implement a true QOS at all, (it just provides
> the parameter interface for part of one its missing the notification
> interface when the service level is not met and I think a few other
> things.) So I wanted to have it named a bit different from just pm_qos.
>
> This said I'm not supper attached to the naming of the modules.  If
> folks want to change it I wouldn't complain (too much anyway;).
Ok got the idea. I do not know what name to chose though. As suggested
previously the name pm_qos_params does not reflect the implementation,
that is why I renamed it.

>
> --mark
> PS I'll look at the rest of the patches tomorrow, this time for real as
> I'm about to have more free time to focus on non-work stuff :)
Thanks you for reviewing!

> FWIW this write up sounds interesting.
Hope it is readable ;p

Regards,
Jean

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-28 13:14 ` [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class mark gross
  2011-07-29  8:37   ` Jean Pihet
@ 2011-07-29  8:37   ` Jean Pihet
  2011-07-29 14:24     ` mark gross
  2011-07-29 14:24     ` mark gross
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:37 UTC (permalink / raw)
  To: markgross
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, broonie, Jean Pihet

Mark,

On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> On Thu, Jul 28, 2011 at 10:30:07AM +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.
>>
>> High level implementation:
>>
...

>> 7. Misc fixes to improve code readability:
>> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> I picked the name for the file as pm_qos_params over pm_qos because I
> wanted to make it implicitly clear that this was not an full QOS
> implementation.  True QOS carries expectations similar to real time and
> as the infrastructure is closer to "good intentioned" than even "best
> effort" and offers no notification when the QOS request is not able to
> be met and really doesn't implement a true QOS at all, (it just provides
> the parameter interface for part of one its missing the notification
> interface when the service level is not met and I think a few other
> things.) So I wanted to have it named a bit different from just pm_qos.
>
> This said I'm not supper attached to the naming of the modules.  If
> folks want to change it I wouldn't complain (too much anyway;).
Ok got the idea. I do not know what name to chose though. As suggested
previously the name pm_qos_params does not reflect the implementation,
that is why I renamed it.

>
> --mark
> PS I'll look at the rest of the patches tomorrow, this time for real as
> I'm about to have more free time to focus on non-work stuff :)
Thanks you for reviewing!

> FWIW this write up sounds interesting.
Hope it is readable ;p

Regards,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29  7:59   ` Todd Poynor
@ 2011-07-29  8:47     ` Jean Pihet
  2011-07-29  8:47     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:47 UTC (permalink / raw)
  To: Todd Poynor
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Todd,

On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
> On Thu, Jul 28, 2011 at 10:30:15AM +0200, jean.pihet@newoldbits.com wrote:
> ...
>> +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_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;
>
> All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
> free_new_user = 1.
free_new_user = 1 is only needed if no existing constraint has been
found, i.e. user stays at NULL. This is implemented in the check for
an existing constraint (plist_for_each_entry(...)).

>(Or maybe change the logic to check user !=
> new_user and free new_user if so.)
That could be done as well.

>
>> +     }
>> +
>> +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);
>
> Need:
>        kfree(new_user);
Correct!
BTW I have a new version (patch here below) that improves the cases
with latency = PM_QOS_DEV_LAT_DEFAULT_VALUE. This will come in v4
after testing.

>
>> +     return ret;
>> +}
>
>
> Todd
>

Thanks for reviewing!

Regards,
Jean

---
Patch for cases with latency = PM_QOS_DEV_LAT_DEFAULT_VALUE:

diff --git a/arch/arm/mach-omap2/powerdomain.c
b/arch/arm/mach-omap2/powerdomain.c
index c0f48ab..2e9379b 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -206,7 +206,7 @@ static int _pwrdm_post_transition_cb(struct
powerdomain *pwrdm, void *unused)
  * 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.
+ *  value of PM_QOS_DEV_LAT_DEFAULT_VALUE means 'no constraint' on the pwrdm.
  *
  * Finds the power domain next power state that fulfills the constraint.
  * Programs a new target state if it is different from current power state.
@@ -232,7 +232,7 @@ static int pwrdm_wakeuplat_update_pwrst(struct
powerdomain *pwrdm,

 	/* Find power state with wakeup latency < minimum constraint */
 	for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) {
-		if (min_latency == 0 ||
+		if (min_latency == PM_QOS_DEV_LAT_DEFAULT_VALUE ||
 		    pwrdm->wakeup_lat[new_state] <= min_latency)
 			break;
 	}
@@ -1018,8 +1018,8 @@ int pwrdm_post_transition(void)
  * @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.
+ *  the given pwrdm. The value of PM_QOS_DEV_LAT_DEFAULT_VALUE removes
+ *  the constraint.
  *
  * Tracks the constraints by @cookie.
  * Constraint set/update: Adds a new entry to powerdomain's wake-up latency
@@ -1042,7 +1042,7 @@ int pwrdm_set_wkup_lat_constraint(struct
powerdomain *pwrdm, void *cookie,
 	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;
+	long value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
 	unsigned long flags;

 	pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
@@ -1083,16 +1083,17 @@ int pwrdm_set_wkup_lat_constraint(struct
powerdomain *pwrdm, void *cookie,
 		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__);
+		if (user) {
+			/* Remove the constraint from the list */
+			plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+			free_node = 1;
+		} else {
+			/* Constraint not existing or list empty, do nothing */
+			free_new_user = 1;
 			ret = -EINVAL;
 			goto exit_error;
 		}

-		plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
-		free_node = 1;
 	}

 exit_ok:
@@ -1117,6 +1118,10 @@ exit_ok:

 exit_error:
 	spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+	if (free_new_user)
+		kfree(new_user);
+
 	return ret;
 }

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29  7:59   ` Todd Poynor
  2011-07-29  8:47     ` Jean Pihet
@ 2011-07-29  8:47     ` Jean Pihet
  2011-07-29 18:00       ` Todd Poynor
  2011-07-29 18:00       ` Todd Poynor
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:47 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet

Todd,

On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
> On Thu, Jul 28, 2011 at 10:30:15AM +0200, jean.pihet@newoldbits.com wrote:
> ...
>> +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_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;
>
> All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
> free_new_user = 1.
free_new_user = 1 is only needed if no existing constraint has been
found, i.e. user stays at NULL. This is implemented in the check for
an existing constraint (plist_for_each_entry(...)).

>(Or maybe change the logic to check user !=
> new_user and free new_user if so.)
That could be done as well.

>
>> +     }
>> +
>> +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);
>
> Need:
>        kfree(new_user);
Correct!
BTW I have a new version (patch here below) that improves the cases
with latency = PM_QOS_DEV_LAT_DEFAULT_VALUE. This will come in v4
after testing.

>
>> +     return ret;
>> +}
>
>
> Todd
>

Thanks for reviewing!

Regards,
Jean

---
Patch for cases with latency = PM_QOS_DEV_LAT_DEFAULT_VALUE:

diff --git a/arch/arm/mach-omap2/powerdomain.c
b/arch/arm/mach-omap2/powerdomain.c
index c0f48ab..2e9379b 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -206,7 +206,7 @@ static int _pwrdm_post_transition_cb(struct
powerdomain *pwrdm, void *unused)
  * 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.
+ *  value of PM_QOS_DEV_LAT_DEFAULT_VALUE means 'no constraint' on the pwrdm.
  *
  * Finds the power domain next power state that fulfills the constraint.
  * Programs a new target state if it is different from current power state.
@@ -232,7 +232,7 @@ static int pwrdm_wakeuplat_update_pwrst(struct
powerdomain *pwrdm,

 	/* Find power state with wakeup latency < minimum constraint */
 	for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) {
-		if (min_latency == 0 ||
+		if (min_latency == PM_QOS_DEV_LAT_DEFAULT_VALUE ||
 		    pwrdm->wakeup_lat[new_state] <= min_latency)
 			break;
 	}
@@ -1018,8 +1018,8 @@ int pwrdm_post_transition(void)
  * @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.
+ *  the given pwrdm. The value of PM_QOS_DEV_LAT_DEFAULT_VALUE removes
+ *  the constraint.
  *
  * Tracks the constraints by @cookie.
  * Constraint set/update: Adds a new entry to powerdomain's wake-up latency
@@ -1042,7 +1042,7 @@ int pwrdm_set_wkup_lat_constraint(struct
powerdomain *pwrdm, void *cookie,
 	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;
+	long value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
 	unsigned long flags;

 	pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
@@ -1083,16 +1083,17 @@ int pwrdm_set_wkup_lat_constraint(struct
powerdomain *pwrdm, void *cookie,
 		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__);
+		if (user) {
+			/* Remove the constraint from the list */
+			plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+			free_node = 1;
+		} else {
+			/* Constraint not existing or list empty, do nothing */
+			free_new_user = 1;
 			ret = -EINVAL;
 			goto exit_error;
 		}

-		plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
-		free_node = 1;
 	}

 exit_ok:
@@ -1117,6 +1118,10 @@ exit_ok:

 exit_error:
 	spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+	if (free_new_user)
+		kfree(new_user);
+
 	return ret;
 }
--
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 related	[flat|nested] 78+ messages in thread

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-29  8:08   ` Todd Poynor
@ 2011-07-29  8:50     ` Jean Pihet
  2011-07-29  8:50     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:50 UTC (permalink / raw)
  To: Todd Poynor
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> The powerdomains next states are initialized in pwrdms_setup as a
>> late_initcall. Because the PM QoS devices constraint can be requested
>> early in the boot sequence, the power domains next states can be
>> overwritten by pwrdms_setup.
>>
>> This patch fixes it by initializing the power domains next states
>> early at boot, so that the constraints can be applied.
>> Later in the pwrdms_setup function the currently programmed
>> next states are re-used as next state values.
>>
>> Applies to OMAP3 and OMAP4.
>>
>> 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>
>> ---
> ...
>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>> index 9af0847..63c3e7a 100644
>> --- a/arch/arm/mach-omap2/powerdomain.c
>> +++ b/arch/arm/mach-omap2/powerdomain.c
>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>       pwrdm->state_counter[pwrdm->state] = 1;
>>
>> +     /* Early init of the next power state */
>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>> +
>
> Wanted to check that it's OK to initialize the next state of a power
> domain to RETENTION early in the boot sequence.  I believe patches
> have been previously discussed that set the state to ON to ensure the
> domain doesn't go to a lower state, and possibly lose context, before
> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
> a doublecheck.
Indeed I need to check the behavior for OMAP3 & 4 which seem to
initialize the pwrdm states differently.
BTW the patch that inits all pwrdms to ON is not yet in l-o master
that is why I (lazily) submitted this one for now.

>
>
> Todd
>
>

Jean

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-29  8:08   ` Todd Poynor
  2011-07-29  8:50     ` Jean Pihet
@ 2011-07-29  8:50     ` Jean Pihet
  2011-08-02  8:57       ` Jean Pihet
  2011-08-02  8:57       ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-07-29  8:50 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet, rnayak

On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> The powerdomains next states are initialized in pwrdms_setup as a
>> late_initcall. Because the PM QoS devices constraint can be requested
>> early in the boot sequence, the power domains next states can be
>> overwritten by pwrdms_setup.
>>
>> This patch fixes it by initializing the power domains next states
>> early at boot, so that the constraints can be applied.
>> Later in the pwrdms_setup function the currently programmed
>> next states are re-used as next state values.
>>
>> Applies to OMAP3 and OMAP4.
>>
>> 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>
>> ---
> ...
>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>> index 9af0847..63c3e7a 100644
>> --- a/arch/arm/mach-omap2/powerdomain.c
>> +++ b/arch/arm/mach-omap2/powerdomain.c
>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>       pwrdm->state_counter[pwrdm->state] = 1;
>>
>> +     /* Early init of the next power state */
>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>> +
>
> Wanted to check that it's OK to initialize the next state of a power
> domain to RETENTION early in the boot sequence.  I believe patches
> have been previously discussed that set the state to ON to ensure the
> domain doesn't go to a lower state, and possibly lose context, before
> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
> a doublecheck.
Indeed I need to check the behavior for OMAP3 & 4 which seem to
initialize the pwrdm states differently.
BTW the patch that inits all pwrdms to ON is not yet in l-o master
that is why I (lazily) submitted this one for now.

>
>
> Todd
>
>

Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29  8:37   ` Jean Pihet
@ 2011-07-29 14:24     ` mark gross
  2011-07-29 14:24     ` mark gross
  1 sibling, 0 replies; 78+ messages in thread
From: mark gross @ 2011-07-29 14:24 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> Mark,
> 
> On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> >>
> >> High level implementation:
> >>
> ...
> 
> >> 7. Misc fixes to improve code readability:
> >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > I picked the name for the file as pm_qos_params over pm_qos because I
> > wanted to make it implicitly clear that this was not an full QOS
> > implementation.  True QOS carries expectations similar to real time and
> > as the infrastructure is closer to "good intentioned" than even "best
> > effort" and offers no notification when the QOS request is not able to
> > be met and really doesn't implement a true QOS at all, (it just provides
> > the parameter interface for part of one its missing the notification
> > interface when the service level is not met and I think a few other
> > things.) So I wanted to have it named a bit different from just pm_qos.
> >
> > This said I'm not supper attached to the naming of the modules.  If
> > folks want to change it I wouldn't complain (too much anyway;).
> Ok got the idea. I do not know what name to chose though. As suggested
> previously the name pm_qos_params does not reflect the implementation,
> that is why I renamed it.

I must have missed the part where the name doesn't reflect the
implementation was talked about.  I look at the interface and I see
parameters all over the place and a small bit of notification.

--mark.

> 
> >
> > --mark
> > PS I'll look at the rest of the patches tomorrow, this time for real as
> > I'm about to have more free time to focus on non-work stuff :)
> Thanks you for reviewing!
> 
> > FWIW this write up sounds interesting.
> Hope it is readable ;p
> 
> Regards,
> Jean

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29  8:37   ` Jean Pihet
  2011-07-29 14:24     ` mark gross
@ 2011-07-29 14:24     ` mark gross
  2011-07-29 21:46       ` Rafael J. Wysocki
  2011-07-29 21:46       ` Rafael J. Wysocki
  1 sibling, 2 replies; 78+ messages in thread
From: mark gross @ 2011-07-29 14:24 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, Rafael J. Wysocki, Paul Walmsley, Kevin Hilman,
	Magnus Damm, Linux PM mailing list, linux-omap, broonie,
	Jean Pihet

On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> Mark,
> 
> On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> >>
> >> High level implementation:
> >>
> ...
> 
> >> 7. Misc fixes to improve code readability:
> >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > I picked the name for the file as pm_qos_params over pm_qos because I
> > wanted to make it implicitly clear that this was not an full QOS
> > implementation.  True QOS carries expectations similar to real time and
> > as the infrastructure is closer to "good intentioned" than even "best
> > effort" and offers no notification when the QOS request is not able to
> > be met and really doesn't implement a true QOS at all, (it just provides
> > the parameter interface for part of one its missing the notification
> > interface when the service level is not met and I think a few other
> > things.) So I wanted to have it named a bit different from just pm_qos.
> >
> > This said I'm not supper attached to the naming of the modules.  If
> > folks want to change it I wouldn't complain (too much anyway;).
> Ok got the idea. I do not know what name to chose though. As suggested
> previously the name pm_qos_params does not reflect the implementation,
> that is why I renamed it.

I must have missed the part where the name doesn't reflect the
implementation was talked about.  I look at the interface and I see
parameters all over the place and a small bit of notification.

--mark.

> 
> >
> > --mark
> > PS I'll look at the rest of the patches tomorrow, this time for real as
> > I'm about to have more free time to focus on non-work stuff :)
> Thanks you for reviewing!
> 
> > FWIW this write up sounds interesting.
> Hope it is readable ;p
> 
> Regards,
> Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29  8:47     ` Jean Pihet
@ 2011-07-29 18:00       ` Todd Poynor
  2011-07-29 18:00       ` Todd Poynor
  1 sibling, 0 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29 18:00 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jul 29, 2011 at 10:47:43AM +0200, Jean Pihet wrote:
> On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
...
> > All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
> > free_new_user = 1.
> free_new_user = 1 is only needed if no existing constraint has been
> found, i.e. user stays at NULL. This is implemented in the check for
> an existing constraint (plist_for_each_entry(...)).

Oops, I meant to say it applies in all cases where min_latency ==
PM_QOS_DEV_LAT_DEFAULT_VALUE, since the new node is only used for
adding a constraint (and no existing constraint found).  I'd suggest
something like:

        if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
                new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
                        GFP_KERNEL);
                <check NULL return>
                free_new_user = 1;
        }

and then set free_new_user = 0 only if no existing constraint is found
for the add case.  Because it's easy to miss cases where the
allocated memory needs to be freed when that's not the default, and you
might as well skip the allocate on a constraint removal.  Pretty minor
point, though.


Todd

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29  8:47     ` Jean Pihet
  2011-07-29 18:00       ` Todd Poynor
@ 2011-07-29 18:00       ` Todd Poynor
  2011-08-11 15:09         ` Jean Pihet
  2011-08-11 15:09         ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Todd Poynor @ 2011-07-29 18:00 UTC (permalink / raw)
  To: Jean Pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet

On Fri, Jul 29, 2011 at 10:47:43AM +0200, Jean Pihet wrote:
> On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
...
> > All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
> > free_new_user = 1.
> free_new_user = 1 is only needed if no existing constraint has been
> found, i.e. user stays at NULL. This is implemented in the check for
> an existing constraint (plist_for_each_entry(...)).

Oops, I meant to say it applies in all cases where min_latency ==
PM_QOS_DEV_LAT_DEFAULT_VALUE, since the new node is only used for
adding a constraint (and no existing constraint found).  I'd suggest
something like:

        if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
                new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
                        GFP_KERNEL);
                <check NULL return>
                free_new_user = 1;
        }

and then set free_new_user = 0 only if no existing constraint is found
for the add case.  Because it's easy to miss cases where the
allocated memory needs to be freed when that's not the default, and you
might as well skip the allocate on a constraint removal.  Pretty minor
point, though.


Todd

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (27 preceding siblings ...)
  2011-07-29 21:25 ` Rafael J. Wysocki
@ 2011-07-29 21:25 ` Rafael J. Wysocki
  28 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:25 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> This patch set is in an RFC state, for review and comments.
> 
> High level implementation:
> 
> 1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_LATENCY).
> . Define a pm_qos_constraints struct for the storage of the constraints list
> and associated values (target_value, default_value, type ...).
> . Update the pm_qos_object struct with the information related to a PM QoS
> class: ptr to constraints list, notifer ptr, name ...
> . Each PM QoS class statically declare objects for pm_qos_object and
> pm_qos_constraints. The only exception is the devices constraints, cf. below.
> . The device constraints class is statically declaring a pm_qos_object. The
> pm_qos_constraints are per-device and so are embedded into the device struct.
> 
> The new class is available from kernel drivers and shall be made available
> to user space through a per-device sysfs entry. User space API to come as a 
> subsequent patch.
> 
> 2. Added a notification of device insertion/removal from the device PM framework
> to PM QoS.
> This allows to init/de-init the per-device constraints list upon device insertion
> and removal.
> RFC state for comments and review, lightly tested
> 
> 3. Make the pm_qos_add_request API more generic by using a
> struct pm_qos_parameters parameter. This allows easy extension in the future.
> 
> 4. Upon a change of the aggregated constraint value in the PM_QOS_DEV_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. 5 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.
> 
> 5. 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_LATENCY class of the PM QoS framework, via the device
> wake-up latency constraints callback to the OMAP_PM_CONSTRAINTS framework.
> 
> 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 those figures.
> 
> 6. Update the pm_qos_add_request callers to the generic API
> 
> 7. Misc fixes to improve code readability:
> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> . rename of fields names (request, list, constraints, class),
> . simplification of the in-kernel PM QoS API implementation. The main logic part
> is now implemented in the update_target function.
> 
> Questions:
> 1. per-device user-space API: since sysfs does not provide open/close
> callbacks it is not possible to support multiple and simultaneous users of
> the per-device sysfs entry. A user-space constraints aggregation application is
> needed in case of multiple constraints for a device. Is this the way to go?

I'd say so.

Thanks,
Rafael

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
                   ` (26 preceding siblings ...)
  2011-07-28 13:14 ` [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class mark gross
@ 2011-07-29 21:25 ` Rafael J. Wysocki
  2011-07-29 21:25 ` Rafael J. Wysocki
  28 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:25 UTC (permalink / raw)
  To: jean.pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> This patch set is in an RFC state, for review and comments.
> 
> High level implementation:
> 
> 1. Add a new PM QoS class for device wake-up constraints (PM_QOS_DEV_LATENCY).
> . Define a pm_qos_constraints struct for the storage of the constraints list
> and associated values (target_value, default_value, type ...).
> . Update the pm_qos_object struct with the information related to a PM QoS
> class: ptr to constraints list, notifer ptr, name ...
> . Each PM QoS class statically declare objects for pm_qos_object and
> pm_qos_constraints. The only exception is the devices constraints, cf. below.
> . The device constraints class is statically declaring a pm_qos_object. The
> pm_qos_constraints are per-device and so are embedded into the device struct.
> 
> The new class is available from kernel drivers and shall be made available
> to user space through a per-device sysfs entry. User space API to come as a 
> subsequent patch.
> 
> 2. Added a notification of device insertion/removal from the device PM framework
> to PM QoS.
> This allows to init/de-init the per-device constraints list upon device insertion
> and removal.
> RFC state for comments and review, lightly tested
> 
> 3. Make the pm_qos_add_request API more generic by using a
> struct pm_qos_parameters parameter. This allows easy extension in the future.
> 
> 4. Upon a change of the aggregated constraint value in the PM_QOS_DEV_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. 5 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.
> 
> 5. 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_LATENCY class of the PM QoS framework, via the device
> wake-up latency constraints callback to the OMAP_PM_CONSTRAINTS framework.
> 
> 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 those figures.
> 
> 6. Update the pm_qos_add_request callers to the generic API
> 
> 7. Misc fixes to improve code readability:
> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> . rename of fields names (request, list, constraints, class),
> . simplification of the in-kernel PM QoS API implementation. The main logic part
> is now implemented in the update_target function.
> 
> Questions:
> 1. per-device user-space API: since sysfs does not provide open/close
> callbacks it is not possible to support multiple and simultaneous users of
> the per-device sysfs entry. A user-space constraints aggregation application is
> needed in case of multiple constraints for a device. Is this the way to go?

I'd say so.

Thanks,
Rafael

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29 14:24     ` mark gross
  2011-07-29 21:46       ` Rafael J. Wysocki
@ 2011-07-29 21:46       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:46 UTC (permalink / raw)
  To: markgross; +Cc: broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Friday, July 29, 2011, mark gross wrote:
> On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> > Mark,
> > 
> > On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> > >>
> > >> High level implementation:
> > >>
> > ...
> > 
> > >> 7. Misc fixes to improve code readability:
> > >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > > I picked the name for the file as pm_qos_params over pm_qos because I
> > > wanted to make it implicitly clear that this was not an full QOS
> > > implementation.  True QOS carries expectations similar to real time and
> > > as the infrastructure is closer to "good intentioned" than even "best
> > > effort" and offers no notification when the QOS request is not able to
> > > be met and really doesn't implement a true QOS at all, (it just provides
> > > the parameter interface for part of one its missing the notification
> > > interface when the service level is not met and I think a few other
> > > things.) So I wanted to have it named a bit different from just pm_qos.
> > >
> > > This said I'm not supper attached to the naming of the modules.  If
> > > folks want to change it I wouldn't complain (too much anyway;).
> > Ok got the idea. I do not know what name to chose though. As suggested
> > previously the name pm_qos_params does not reflect the implementation,
> > that is why I renamed it.
> 
> I must have missed the part where the name doesn't reflect the
> implementation was talked about.  I look at the interface and I see
> parameters all over the place and a small bit of notification.

The interface is for specifying PM QoS requirements or constraints that
may or may not be regarded as "parameters", depending on ones definition
of the last term.  Moreover, the code not only implements the interface,
but also defines data structures and API to be used throughout the kernel
which is quite a bit more than just "parameters".

In my not so humble opinion the name isn't good and the .c file should be
in kernel/power in the first place.  I would call it simply qos.c (the fact
that _right_ _now_ it's not a full QoS implementation doesn't matter, because
it may become one in the future).

Thanks,
Rafael

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29 14:24     ` mark gross
@ 2011-07-29 21:46       ` Rafael J. Wysocki
  2011-07-31 17:38         ` mark gross
  2011-07-31 17:38         ` [linux-pm] " mark gross
  2011-07-29 21:46       ` Rafael J. Wysocki
  1 sibling, 2 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:46 UTC (permalink / raw)
  To: markgross
  Cc: Jean Pihet, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, broonie, Jean Pihet

On Friday, July 29, 2011, mark gross wrote:
> On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> > Mark,
> > 
> > On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> > >>
> > >> High level implementation:
> > >>
> > ...
> > 
> > >> 7. Misc fixes to improve code readability:
> > >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > > I picked the name for the file as pm_qos_params over pm_qos because I
> > > wanted to make it implicitly clear that this was not an full QOS
> > > implementation.  True QOS carries expectations similar to real time and
> > > as the infrastructure is closer to "good intentioned" than even "best
> > > effort" and offers no notification when the QOS request is not able to
> > > be met and really doesn't implement a true QOS at all, (it just provides
> > > the parameter interface for part of one its missing the notification
> > > interface when the service level is not met and I think a few other
> > > things.) So I wanted to have it named a bit different from just pm_qos.
> > >
> > > This said I'm not supper attached to the naming of the modules.  If
> > > folks want to change it I wouldn't complain (too much anyway;).
> > Ok got the idea. I do not know what name to chose though. As suggested
> > previously the name pm_qos_params does not reflect the implementation,
> > that is why I renamed it.
> 
> I must have missed the part where the name doesn't reflect the
> implementation was talked about.  I look at the interface and I see
> parameters all over the place and a small bit of notification.

The interface is for specifying PM QoS requirements or constraints that
may or may not be regarded as "parameters", depending on ones definition
of the last term.  Moreover, the code not only implements the interface,
but also defines data structures and API to be used throughout the kernel
which is quite a bit more than just "parameters".

In my not so humble opinion the name isn't good and the .c file should be
in kernel/power in the first place.  I would call it simply qos.c (the fact
that _right_ _now_ it's not a full QoS implementation doesn't matter, because
it may become one in the future).

Thanks,
Rafael

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

* Re: [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-29 21:57   ` Rafael J. Wysocki
  2011-08-02  9:31     ` Jean Pihet
  0 siblings, 1 reply; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:57 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> The PM QoS implementation files are better named
> kernel/pm_qos.c and include/linux/pm_qos.h.
> 
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  arch/arm/mach-msm/clock.c              |    2 +-
>  drivers/acpi/processor_idle.c          |    2 +-
>  drivers/cpuidle/cpuidle.c              |    2 +-
>  drivers/cpuidle/governors/ladder.c     |    2 +-
>  drivers/cpuidle/governors/menu.c       |    2 +-
>  drivers/media/video/via-camera.c       |    2 +-
>  drivers/net/e1000e/netdev.c            |    2 +-
>  drivers/net/wireless/ipw2x00/ipw2100.c |    2 +-
>  drivers/staging/msm/lcdc.c             |    2 +-
>  drivers/staging/msm/tvenc.c            |    2 +-
>  include/linux/netdevice.h              |    2 +-
>  include/linux/pm_qos.h                 |   38 +++
>  include/linux/pm_qos_params.h          |   38 ---
>  include/sound/pcm.h                    |    2 +-
>  kernel/Makefile                        |    2 +-
>  kernel/pm_qos.c                        |  481 ++++++++++++++++++++++++++++++++
>  kernel/pm_qos_params.c                 |  481 --------------------------------
>  net/mac80211/main.c                    |    2 +-
>  net/mac80211/mlme.c                    |    2 +-
>  net/mac80211/scan.c                    |    2 +-
>  sound/core/pcm_native.c                |    2 +-
>  21 files changed, 536 insertions(+), 536 deletions(-)
>  create mode 100644 include/linux/pm_qos.h
>  delete mode 100644 include/linux/pm_qos_params.h

That I agree with.

>  create mode 100644 kernel/pm_qos.c
>  delete mode 100644 kernel/pm_qos_params.c

As I said, please move that file to kernel/power and call it qos.c.

That said the device interface should be located in drivers/base/power
to follow our current conventions.

Thanks,
Rafael

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

* Re: [PATCH 02/13] PM: add a per-device wake-up latency constraints plist
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-29 21:58   ` Rafael J. Wysocki
  2011-07-29 21:58   ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:58 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Add the field latency_constraints 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>

This one looks good to me.

Thanks,
Rafael


> ---
>  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 06f09bf..dad2eb9 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,6 +97,7 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> +	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
>  }
>  
>  /**
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 411e4f4..23c85f1 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>
> @@ -463,6 +464,7 @@ struct dev_pm_info {
>  	unsigned long		accounting_timestamp;
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
> +	struct plist_head	latency_constraints;
>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> 

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

* Re: [PATCH 02/13] PM: add a per-device wake-up latency constraints plist
  2011-07-28  8:30 ` jean.pihet
  2011-07-29 21:58   ` Rafael J. Wysocki
@ 2011-07-29 21:58   ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 21:58 UTC (permalink / raw)
  To: jean.pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Add the field latency_constraints 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>

This one looks good to me.

Thanks,
Rafael


> ---
>  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 06f09bf..dad2eb9 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,6 +97,7 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> +	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
>  }
>  
>  /**
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 411e4f4..23c85f1 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>
> @@ -463,6 +464,7 @@ struct dev_pm_info {
>  	unsigned long		accounting_timestamp;
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
> +	struct plist_head	latency_constraints;
>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> 


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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-29 22:55   ` Rafael J. Wysocki
  2011-07-29 22:55   ` Rafael J. Wysocki
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 22:55 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Extend the PM QoS kernel API:
> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
> constraints
> - make the pm_qos_add_request API more generic by using a parameter of
> type struct pm_qos_parameters
> - minor clean-ups and rename of struct fields:
>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>   . consistenly use req and params as the API parameters
>   . rename struct pm_qos_request_list to struct pm_qos_request
> - update the in-kernel API callers to the new API

There should be more about the motivation in the changelog.  It says
what the patch is doing, but it doesn't say a word of _why_ it is done in
the first place.

Second, you're renaming a lot of things in the same patch that makes
functional changes.  This is confusing and makes it very difficult to
understand what's going on.  Please use separate patches to rename
things, when possible, and avoid renaming things that don't need to be
renamed.

> 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       |    7 +-
>  drivers/net/e1000e/netdev.c            |    9 ++-
>  drivers/net/wireless/ipw2x00/ipw2100.c |    8 +-
>  include/linux/netdevice.h              |    2 +-
>  include/linux/pm_qos.h                 |   39 ++++++----
>  include/sound/pcm.h                    |    2 +-
>  kernel/pm_qos.c                        |  130 +++++++++++++++++--------------
>  sound/core/pcm_native.c                |    8 ++-
>  10 files changed, 141 insertions(+), 119 deletions(-)

I'm going to comment the core changes this time.

...
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index 9cc0224..a2e4409 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -8,31 +8,40 @@
>  #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_LATENCY		2
> +#define PM_QOS_NETWORK_LATENCY		3
> +#define PM_QOS_NETWORK_THROUGHPUT	4
>  
> -#define PM_QOS_NUM_CLASSES 4
> +#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_DEV_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 pm_qos_request {

This renaming should go in a separate patch, really.

>  	struct plist_node list;
> -	int pm_qos_class;
> +	int class;

This renaming doesn't seem to be necessary.  Moreover, it's confusing,
because there already is struct class (for device classes) and a member
called "class" in struct device and they aren't related to this one.

> +	struct device *dev;
>  };
>  
> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> -		s32 new_value);
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> +struct pm_qos_parameters {
> +	int class;
> +	struct device *dev;
> +	s32 value;
> +};

What exactly is the "dev" member needed for?

> +
> +void pm_qos_add_request(struct pm_qos_request *req,
> +			struct pm_qos_parameters *params);
> +void pm_qos_update_request(struct pm_qos_request *req, s32 new_value);
> +void pm_qos_remove_request(struct pm_qos_request *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_active(struct pm_qos_request_list *req);
> +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 *req);
>  
>  #endif
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 1204f17..d3b068f 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -373,7 +373,7 @@ struct snd_pcm_substream {
>  	int number;
>  	char name[32];			/* substream name */
>  	int stream;			/* stream (direction) */
> -	struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
> +	struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
>  	size_t buffer_bytes_max;	/* limit ring buffer size */
>  	struct snd_dma_buffer dma_buffer;
>  	unsigned int dma_buf_id;
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 3bf69f1..4ede3cd 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -82,6 +82,16 @@ static struct pm_qos_object cpu_dma_pm_qos = {
>  	.type = PM_QOS_MIN,
>  };
>  
> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
> +static struct pm_qos_object dev_pm_qos = {
> +	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> +	.notifiers = &dev_lat_notifier,
> +	.name = "dev_latency",
> +	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> +	.type = PM_QOS_MIN,
> +};
> +

You seem to be confusing things here.  Since devices will have their own lists
of requests now (as per the previous patch), the .requests member above is not
necessary.  Moreover, it seems to be used incorrectly below.

>  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 +117,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_pm_qos,
>  	&network_lat_pm_qos,
>  	&network_throughput_pm_qos
>  };
> @@ -212,132 +223,132 @@ static int find_pm_qos_object_by_minor(int minor)
>  
>  /**
>   * 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]);
> +	return pm_qos_read_value(pm_qos_array[class]);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_request);

As I said, it is completely unnecessary (and confusing) to rename
"pm_qos_class" to "class".

> -int pm_qos_request_active(struct pm_qos_request_list *req)
> +int pm_qos_request_active(struct pm_qos_request *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
> + * @req: pointer to a preallocated handle
> + * @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
> + * for the class of parameters and initializes the pm_qos_request
>   * 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 *req,
> +			struct pm_qos_parameters *params)
>  {
> -	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
> +	struct pm_qos_object *o =  pm_qos_array[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_request_active(req)) {
> +		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
> +			"added request\n");
>  		return;
>  	}
> -	if (value == PM_QOS_DEFAULT_VALUE)
> +	if (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 = params->value;
> +	plist_node_init(&req->list, new_value);
> +	req->class = params->class;
> +	req->dev = params->dev;
> +	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);

This causes update_target() to use the .requests member of dev_pm_qos
as a list of requests for every device, which doesn't seem to be correct.

>  }
>  EXPORT_SYMBOL_GPL(pm_qos_add_request);
>  
>  /**
>   * pm_qos_update_request - modifies an existing qos request
> - * @pm_qos_req : handle to list element holding a pm_qos request to use
> + * @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.
>   */
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> -			   s32 new_value)
> +void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  {
>  	s32 temp;
>  	struct pm_qos_object *o;
>  
> -	if (!pm_qos_req) /*guard against callers passing in null */
> +	if (!req) /*guard against callers passing in null */
>  		return;
>  
> -	if (!pm_qos_request_active(pm_qos_req)) {
> +	if (!pm_qos_request_active(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];
> +	o = pm_qos_array[req->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);
> +	if (temp != req->list.prio)
> +		update_target(o, &req->list, 0, temp);

Same here.

>  }
>  EXPORT_SYMBOL_GPL(pm_qos_update_request);
>  
>  /**
>   * pm_qos_remove_request - modifies an existing qos request
> - * @pm_qos_req: handle to request list element
> + * @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)
> +void pm_qos_remove_request(struct pm_qos_request *req)
>  {
>  	struct pm_qos_object *o;
>  
> -	if (pm_qos_req == NULL)
> +	if (req == NULL)
>  		return;
>  		/* silent return to keep pcm code cleaner */
>  
> -	if (!pm_qos_request_active(pm_qos_req)) {
> +	if (!pm_qos_request_active(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);
> -	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
> +	o = pm_qos_array[req->class];
> +	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);

Same here.

> +	memset(req, 0, sizeof(*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);

Now, there's a question if we want to have one notifier chain for all
devices or if it's better to have a per-device notifier chain.  Both
approaches have their own advantages and drawbacks, but in the latter
case this code will have to be reworked.

Thanks,
Rafael

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
  2011-07-29 22:55   ` Rafael J. Wysocki
@ 2011-07-29 22:55   ` Rafael J. Wysocki
  2011-08-02  9:41     ` Jean Pihet
  2011-08-02  9:41     ` Jean Pihet
  2011-08-02 18:01   ` Kevin Hilman
  2011-08-02 18:01   ` Kevin Hilman
  3 siblings, 2 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-29 22:55 UTC (permalink / raw)
  To: jean.pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Extend the PM QoS kernel API:
> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
> constraints
> - make the pm_qos_add_request API more generic by using a parameter of
> type struct pm_qos_parameters
> - minor clean-ups and rename of struct fields:
>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>   . consistenly use req and params as the API parameters
>   . rename struct pm_qos_request_list to struct pm_qos_request
> - update the in-kernel API callers to the new API

There should be more about the motivation in the changelog.  It says
what the patch is doing, but it doesn't say a word of _why_ it is done in
the first place.

Second, you're renaming a lot of things in the same patch that makes
functional changes.  This is confusing and makes it very difficult to
understand what's going on.  Please use separate patches to rename
things, when possible, and avoid renaming things that don't need to be
renamed.

> 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       |    7 +-
>  drivers/net/e1000e/netdev.c            |    9 ++-
>  drivers/net/wireless/ipw2x00/ipw2100.c |    8 +-
>  include/linux/netdevice.h              |    2 +-
>  include/linux/pm_qos.h                 |   39 ++++++----
>  include/sound/pcm.h                    |    2 +-
>  kernel/pm_qos.c                        |  130 +++++++++++++++++--------------
>  sound/core/pcm_native.c                |    8 ++-
>  10 files changed, 141 insertions(+), 119 deletions(-)

I'm going to comment the core changes this time.

...
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index 9cc0224..a2e4409 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -8,31 +8,40 @@
>  #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_LATENCY		2
> +#define PM_QOS_NETWORK_LATENCY		3
> +#define PM_QOS_NETWORK_THROUGHPUT	4
>  
> -#define PM_QOS_NUM_CLASSES 4
> +#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_DEV_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 pm_qos_request {

This renaming should go in a separate patch, really.

>  	struct plist_node list;
> -	int pm_qos_class;
> +	int class;

This renaming doesn't seem to be necessary.  Moreover, it's confusing,
because there already is struct class (for device classes) and a member
called "class" in struct device and they aren't related to this one.

> +	struct device *dev;
>  };
>  
> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> -		s32 new_value);
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> +struct pm_qos_parameters {
> +	int class;
> +	struct device *dev;
> +	s32 value;
> +};

What exactly is the "dev" member needed for?

> +
> +void pm_qos_add_request(struct pm_qos_request *req,
> +			struct pm_qos_parameters *params);
> +void pm_qos_update_request(struct pm_qos_request *req, s32 new_value);
> +void pm_qos_remove_request(struct pm_qos_request *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_active(struct pm_qos_request_list *req);
> +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 *req);
>  
>  #endif
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 1204f17..d3b068f 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -373,7 +373,7 @@ struct snd_pcm_substream {
>  	int number;
>  	char name[32];			/* substream name */
>  	int stream;			/* stream (direction) */
> -	struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
> +	struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
>  	size_t buffer_bytes_max;	/* limit ring buffer size */
>  	struct snd_dma_buffer dma_buffer;
>  	unsigned int dma_buf_id;
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 3bf69f1..4ede3cd 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -82,6 +82,16 @@ static struct pm_qos_object cpu_dma_pm_qos = {
>  	.type = PM_QOS_MIN,
>  };
>  
> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
> +static struct pm_qos_object dev_pm_qos = {
> +	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> +	.notifiers = &dev_lat_notifier,
> +	.name = "dev_latency",
> +	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> +	.type = PM_QOS_MIN,
> +};
> +

You seem to be confusing things here.  Since devices will have their own lists
of requests now (as per the previous patch), the .requests member above is not
necessary.  Moreover, it seems to be used incorrectly below.

>  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 +117,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_pm_qos,
>  	&network_lat_pm_qos,
>  	&network_throughput_pm_qos
>  };
> @@ -212,132 +223,132 @@ static int find_pm_qos_object_by_minor(int minor)
>  
>  /**
>   * 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]);
> +	return pm_qos_read_value(pm_qos_array[class]);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_request);

As I said, it is completely unnecessary (and confusing) to rename
"pm_qos_class" to "class".

> -int pm_qos_request_active(struct pm_qos_request_list *req)
> +int pm_qos_request_active(struct pm_qos_request *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
> + * @req: pointer to a preallocated handle
> + * @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
> + * for the class of parameters and initializes the pm_qos_request
>   * 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 *req,
> +			struct pm_qos_parameters *params)
>  {
> -	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
> +	struct pm_qos_object *o =  pm_qos_array[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_request_active(req)) {
> +		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
> +			"added request\n");
>  		return;
>  	}
> -	if (value == PM_QOS_DEFAULT_VALUE)
> +	if (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 = params->value;
> +	plist_node_init(&req->list, new_value);
> +	req->class = params->class;
> +	req->dev = params->dev;
> +	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);

This causes update_target() to use the .requests member of dev_pm_qos
as a list of requests for every device, which doesn't seem to be correct.

>  }
>  EXPORT_SYMBOL_GPL(pm_qos_add_request);
>  
>  /**
>   * pm_qos_update_request - modifies an existing qos request
> - * @pm_qos_req : handle to list element holding a pm_qos request to use
> + * @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.
>   */
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> -			   s32 new_value)
> +void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  {
>  	s32 temp;
>  	struct pm_qos_object *o;
>  
> -	if (!pm_qos_req) /*guard against callers passing in null */
> +	if (!req) /*guard against callers passing in null */
>  		return;
>  
> -	if (!pm_qos_request_active(pm_qos_req)) {
> +	if (!pm_qos_request_active(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];
> +	o = pm_qos_array[req->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);
> +	if (temp != req->list.prio)
> +		update_target(o, &req->list, 0, temp);

Same here.

>  }
>  EXPORT_SYMBOL_GPL(pm_qos_update_request);
>  
>  /**
>   * pm_qos_remove_request - modifies an existing qos request
> - * @pm_qos_req: handle to request list element
> + * @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)
> +void pm_qos_remove_request(struct pm_qos_request *req)
>  {
>  	struct pm_qos_object *o;
>  
> -	if (pm_qos_req == NULL)
> +	if (req == NULL)
>  		return;
>  		/* silent return to keep pcm code cleaner */
>  
> -	if (!pm_qos_request_active(pm_qos_req)) {
> +	if (!pm_qos_request_active(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);
> -	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
> +	o = pm_qos_array[req->class];
> +	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);

Same here.

> +	memset(req, 0, sizeof(*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);

Now, there's a question if we want to have one notifier chain for all
devices or if it's better to have a per-device notifier chain.  Both
approaches have their own advantages and drawbacks, but in the latter
case this code will have to be reworked.

Thanks,
Rafael

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
  2011-07-30 22:30   ` Rafael J. Wysocki
@ 2011-07-30 22:30   ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-30 22:30 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Re-design the PM QoS implementation to support the per-device
> constraints:

Well, I guess I should have reviewed this patch before [03/13].

> - Define a pm_qos_constraints struct for the storage of the constraints
> list and associated values (target_value, default_value, type ...).
> 
> - Update the pm_qos_object struct with the information related to a
> PM QoS class: ptr to constraints list, notifer ptr, name ...
> 
> - Each PM QoS class statically declare objects for pm_qos_object and
> pm_qos_constraints. The only exception is the devices constraints, cf. below.
> 
> - The device constraints class is statically declaring a pm_qos_object. The
> pm_qos_constraints are per-device and so are embedded into the device struct.
> 
> - The PM QoS internal functions are updated to operate on the pm_qos_constraints
> structs for the constraints management, and on pm_qos_object for other the PM QoS
> functionality (notifiers, export as misc devices...).
> 
> - The PM QoS events notification callbacks are passing the full constraint
> request data in order for the callees to have access to it. The current use
> is for the platform low-level code to access the target device of the constraint
> 
> - User space API: the PM QoS classes -excepted PM_QOS_DEV_LATENCY- are exporting
> a MISC entry in /dev. PM_QOS_DEV_LATENCY shall export a per-device sysfs entry, this
> support is coming as a subsequent patch.
> 
> - Misc fixes to improve code readability:
>   . rename of fields names (request, list, constraints, class),

Please avoid doing renames along with functional changes.  It makes reviewing
extremely hard.

>   . simplification of the in-kernel API implementation. The main logic part is
>     now implemented in the update_target function.
> 
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  drivers/base/power/main.c |    7 +-
>  include/linux/pm.h        |    3 +-
>  include/linux/pm_qos.h    |   23 ++++-
>  kernel/pm_qos.c           |  248 +++++++++++++++++++++++++-------------------
>  4 files changed, 170 insertions(+), 111 deletions(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index dad2eb9..360c2c0 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> -	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +	dev->power.latency_constraints.target_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.default_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.type = PM_QOS_MIN;

Perhaps add a helper doing these assignments?

>  }
>  
>  /**
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 23c85f1..35e48a3 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -28,6 +28,7 @@
>  #include <linux/wait.h>
>  #include <linux/timer.h>
>  #include <linux/completion.h>
> +#include <linux/pm_qos.h>
>  
>  /*
>   * Callbacks for platform drivers to implement.
> @@ -464,7 +465,7 @@ struct dev_pm_info {
>  	unsigned long		accounting_timestamp;
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
> -	struct plist_head	latency_constraints;
> +	struct pm_qos_constraints	latency_constraints;

Why don't you simply call it "qos"?  The data type provides the information
about what it's for now.

>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index a2e4409..d72b16b 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -6,7 +6,6 @@
>   */
>  #include <linux/plist.h>
>  #include <linux/notifier.h>
> -#include <linux/miscdevice.h>
>  
>  #define PM_QOS_RESERVED			0
>  #define PM_QOS_CPU_DMA_LATENCY		1
> @@ -22,8 +21,28 @@
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  
> +enum pm_qos_type {
> +	PM_QOS_MAX,		/* return the largest value */
> +	PM_QOS_MIN		/* return the smallest value */
> +};
> +
> +struct pm_qos_constraints {
> +	struct plist_head list;
> +	/*
> +	 * Do not change target_value to 64 bit in order to guarantee
> +	 * accesses atomicity
> +	 */

The comment doesn't belong here.  Please put it outside of the structure
definition or after the field name (or both, in which case the "inline"
one may be shorter, like "must not be 64-bit").

> +	s32 target_value;
> +	s32 default_value;
> +	enum pm_qos_type type;
> +};
> +
> +/*
> + * Struct that is pre-allocated by the caller.
> + * The handle is kept for future use (update, removal)
> + */
>  struct pm_qos_request {
> -	struct plist_node list;
> +	struct plist_node node;

Please avoid doing such things along with functional changes.

>  	int class;
>  	struct device *dev;
>  };
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 4ede3cd..7edc6d0 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -49,71 +49,81 @@
>   * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
>   * held, taken with _irqsave.  One lock to rule them all
>   */
> -enum pm_qos_type {
> -	PM_QOS_MAX,		/* return the largest value */
> -	PM_QOS_MIN		/* return the smallest value */
> +
> +enum pm_qos_req_action {
> +	PM_QOS_ADD_REQ,
> +	PM_QOS_UPDATE_REQ,
> +	PM_QOS_REMOVE_REQ
>  };

A comment describing the meaning of these would be helpful.
  
> -/*
> - * Note: The lockless read path depends on the CPU accessing
> - * target_value atomically.  Atomic access is only guaranteed on all CPU
> - * types linux supports for 32 bit quantites
> - */
>  struct pm_qos_object {
> -	struct plist_head requests;
> +	struct pm_qos_constraints *constraints;
>  	struct blocking_notifier_head *notifiers;
>  	struct miscdevice pm_qos_power_miscdev;
>  	char *name;
> -	s32 target_value;	/* Do not change to 64 bit */
> -	s32 default_value;
> -	enum pm_qos_type type;
>  };
>  
>  static DEFINE_SPINLOCK(pm_qos_lock);
>  
>  static struct pm_qos_object null_pm_qos;
> +
> +/* CPU/DMA latency constraints PM QoS object */
> +static struct pm_qos_constraints cpu_dma_constraints = {
> +	.list = PLIST_HEAD_INIT(cpu_dma_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> +	.type = PM_QOS_MIN,
> +};
>  static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
>  static struct pm_qos_object cpu_dma_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
> +	.constraints = &cpu_dma_constraints,
>  	.notifiers = &cpu_dma_lat_notifier,
>  	.name = "cpu_dma_latency",
> -	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN,
>  };
>  
> +/*
> + * Per-device latency constraints PM QoS object
> + *
> + * The constraints are stored in the device struct data.
> + * No misc device is exported to /dev, instead the user space API
> + * shall use a per-device /sysfs entry.
> + */
>  static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
>  static struct pm_qos_object dev_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> +	.constraints = NULL,
>  	.notifiers = &dev_lat_notifier,
> +	.pm_qos_power_miscdev = { .minor = -1 },
>  	.name = "dev_latency",
> -	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN,
>  };
>  
> +/* Network latency constraints PM QoS object */
> +static struct pm_qos_constraints network_lat_constraints = {
> +	.list = PLIST_HEAD_INIT(network_lat_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_NETWORK_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),
> +	.constraints = &network_lat_constraints,
>  	.notifiers = &network_lat_notifier,
>  	.name = "network_latency",
> -	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN
>  };
>  
> -
> +/* Network throughput constraints PM QoS object */
> +static struct pm_qos_constraints network_tput_constraints = {
> +	.list = PLIST_HEAD_INIT(network_tput_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> +	.type = PM_QOS_MAX,
> +};
>  static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
>  static struct pm_qos_object network_throughput_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
> +	.constraints = &network_tput_constraints,
>  	.notifiers = &network_throughput_notifier,
>  	.name = "network_throughput",
> -	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> -	.type = PM_QOS_MAX,
>  };
>  
> -
>  static struct pm_qos_object *pm_qos_array[] = {
>  	&null_pm_qos,
>  	&cpu_dma_pm_qos,
> @@ -138,17 +148,17 @@ static const struct file_operations pm_qos_power_fops = {
>  };
>  
>  /* unlocked internal variant */
> -static inline int pm_qos_get_value(struct pm_qos_object *o)
> +static inline int pm_qos_get_value(struct pm_qos_constraints *c)

I'd remove the "inline" if you're at it.  It's only a hint if the kernel
is not built with "always inline" and the compiler should do the inlining
anyway if that's a better choice.

>  {
> -	if (plist_head_empty(&o->requests))
> -		return o->default_value;
> +	if (plist_head_empty(&c->list))
> +		return c->default_value;
>  
> -	switch (o->type) {
> +	switch (c->type) {
>  	case PM_QOS_MIN:
> -		return plist_first(&o->requests)->prio;
> +		return plist_first(&c->list)->prio;
>  
>  	case PM_QOS_MAX:
> -		return plist_last(&o->requests)->prio;
> +		return plist_last(&c->list)->prio;
>  
>  	default:
>  		/* runtime check for not using enum */
> @@ -156,69 +166,92 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
>  	}
>  }
>  
> -static inline s32 pm_qos_read_value(struct pm_qos_object *o)
> +/*
> + * pm_qos_read_value atomically reads and returns target_value.

We have a standard for writing kerneldoc comments, please follow it.

> + * target_value is updated upon update of the constraints list, using
> + * pm_qos_set_value.
> + *
> + * Note: The lockless read path depends on the CPU accessing
> + * target_value atomically.  Atomic access is only guaranteed on all CPU
> + * types linux supports for 32 bit quantites

You should say "data types" rather than "quantities" here.

> + */
> +static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
>  {
> -	return o->target_value;
> +	if (c)
> +		return c->target_value;
> +	else
> +		return 0;
>  }
>  
> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
>  {
> -	o->target_value = value;
> +	c->target_value = value;
>  }

Well, I'm not sure that this function is necessary at all.  You might as well
simply remove it as far as I'm concerned.

> -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 *req,
> +			  enum pm_qos_req_action action, int value)
>  {
>  	unsigned long flags;
> -	int prev_value, curr_value;
> +	int prev_value, curr_value, new_value;
> +	struct pm_qos_object *o = pm_qos_array[req->class];
> +	struct pm_qos_constraints *c;
> +
> +	switch (req->class) {
> +	case PM_QOS_DEV_LATENCY:
> +		if (!req->dev) {
> +			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
> +			return;
> +		}
> +		c = &req->dev->power.latency_constraints;
> +		break;
> +	case PM_QOS_CPU_DMA_LATENCY:
> +	case PM_QOS_NETWORK_LATENCY:
> +	case PM_QOS_NETWORK_THROUGHPUT:
> +		c = o->constraints;
> +		break;
> +	case PM_QOS_RESERVED:
> +	default:
> +		WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
> +			"req 0x%p\n", req->class, req);
> +		return;
> +	}

Do we _really_ need that switch()?

What about introducing dev_pm_qos_add_request() and friends specifically
for devices, such that they will take the target device object (dev) as
their first argument?  Then, you could keep pm_qos_add_request() pretty
much as is, right?

>  
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	prev_value = pm_qos_get_value(o);
> -	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> -	if (value != PM_QOS_DEFAULT_VALUE) {
> +
> +	prev_value = pm_qos_get_value(c);
> +	if (value == PM_QOS_DEFAULT_VALUE)
> +		new_value = c->default_value;
> +	else
> +		new_value = value;

What about writing that as

	new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;

> +
> +	switch (action) {
> +	case PM_QOS_REMOVE_REQ:
> +		plist_del(&req->node, &c->list);
> +		break;
> +	case PM_QOS_UPDATE_REQ:
>  		/*
>  		 * to change the list, we atomically remove, reinit
>  		 * with new value and add, then see if the extremal
>  		 * changed
>  		 */
> -		plist_del(node, &o->requests);
> -		plist_node_init(node, value);
> -		plist_add(node, &o->requests);
> -	} else if (del) {
> -		plist_del(node, &o->requests);
> -	} else {
> -		plist_add(node, &o->requests);
> +		plist_del(&req->node, &c->list);
> +	case PM_QOS_ADD_REQ:
> +		plist_node_init(&req->node, new_value);
> +		plist_add(&req->node, &c->list);
> +		break;
> +	default:
> +		/* no action */
> +		;
>  	}
> -	curr_value = pm_qos_get_value(o);
> -	pm_qos_set_value(o, curr_value);
> +
> +	curr_value = pm_qos_get_value(c);
> +	pm_qos_set_value(c, curr_value);
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  
>  	if (prev_value != curr_value)
>  		blocking_notifier_call_chain(o->notifiers,

That's why I'm thinking that it would be helpful to have a pointer
to the notifier list from struct pm_qos_constraints .

Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
"o->notifiers".

>  					     (unsigned long)curr_value,
> -					     NULL);
> -}
> -
> -static int register_pm_qos_misc(struct pm_qos_object *qos)
> -{
> -	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> -	qos->pm_qos_power_miscdev.name = qos->name;
> -	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> -
> -	return misc_register(&qos->pm_qos_power_miscdev);
> -}
> -
> -static int find_pm_qos_object_by_minor(int minor)
> -{
> -	int pm_qos_class;
> -
> -	for (pm_qos_class = 0;
> -		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> -		if (minor ==
> -			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> -			return pm_qos_class;
> -	}
> -	return -1;
> +					     req);
>  }
>  
>  /**
> @@ -229,7 +262,7 @@ static int find_pm_qos_object_by_minor(int minor)
>   */
>  int pm_qos_request(int class)
>  {
> -	return pm_qos_read_value(pm_qos_array[class]);
> +	return pm_qos_read_value(pm_qos_array[class]->constraints);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_request);
>  
> @@ -254,22 +287,15 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
>  void pm_qos_add_request(struct pm_qos_request *req,
>  			struct pm_qos_parameters *params)
>  {
> -	struct pm_qos_object *o =  pm_qos_array[params->class];
> -	int new_value;
> -
>  	if (pm_qos_request_active(req)) {
>  		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
>  			"added request\n");
>  		return;
>  	}
> -	if (params->value == PM_QOS_DEFAULT_VALUE)
> -		new_value = o->default_value;
> -	else
> -		new_value = params->value;
> -	plist_node_init(&req->list, new_value);
> +
>  	req->class = params->class;
>  	req->dev = params->dev;
> -	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
> +	update_target(req, PM_QOS_ADD_REQ, params->value);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_add_request);
>  
> @@ -285,9 +311,6 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
>   */
>  void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  {
> -	s32 temp;
> -	struct pm_qos_object *o;
> -
>  	if (!req) /*guard against callers passing in null */
>  		return;
>  
> @@ -296,15 +319,8 @@ void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  		return;
>  	}
>  
> -	o = pm_qos_array[req->class];
> -
> -	if (new_value == PM_QOS_DEFAULT_VALUE)
> -		temp = o->default_value;
> -	else
> -		temp = new_value;
> -
> -	if (temp != req->list.prio)
> -		update_target(o, &req->list, 0, temp);
> +	if (new_value != req->node.prio)
> +		update_target(req, PM_QOS_UPDATE_REQ, new_value);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_update_request);
>  
> @@ -318,8 +334,6 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
>   */
>  void pm_qos_remove_request(struct pm_qos_request *req)
>  {
> -	struct pm_qos_object *o;
> -
>  	if (req == NULL)
>  		return;
>  		/* silent return to keep pcm code cleaner */
> @@ -329,8 +343,8 @@ void pm_qos_remove_request(struct pm_qos_request *req)
>  		return;
>  	}
>  
> -	o = pm_qos_array[req->class];
> -	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
> +	update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
> +
>  	memset(req, 0, sizeof(*req));
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_request);
> @@ -373,6 +387,28 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
>  
> +static int register_pm_qos_misc(struct pm_qos_object *qos)
> +{
> +	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> +	qos->pm_qos_power_miscdev.name = qos->name;
> +	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> +
> +	return misc_register(&qos->pm_qos_power_miscdev);
> +}
> +
> +static int find_pm_qos_object_by_minor(int minor)
> +{
> +	int pm_qos_class;
> +
> +	for (pm_qos_class = 0;
> +		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> +		if (minor ==
> +			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> +			return pm_qos_class;
> +	}
> +	return -1;
> +}

This function doesn't seem to be used anywhere, what's the purpose of it?

> +
>  static int pm_qos_power_open(struct inode *inode, struct file *filp)
>  {
>  	struct pm_qos_parameters pm_qos_params;
> @@ -410,7 +446,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
>  {
>  	s32 value;
>  	unsigned long flags;
> -	struct pm_qos_object *o;
>  	struct pm_qos_request *req = filp->private_data;
>  
>  	if (!req)
> @@ -418,9 +453,8 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
>  	if (!pm_qos_request_active(req))
>  		return -EINVAL;
>  
> -	o = pm_qos_array[req->class];
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	value = pm_qos_get_value(o);
> +	value = pm_qos_get_value(pm_qos_array[req->class]->constraints);
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  
>  	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));

Thanks,
Rafael

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-30 22:30   ` Rafael J. Wysocki
  2011-08-02 10:05     ` Jean Pihet
  2011-08-02 10:05     ` Jean Pihet
  2011-07-30 22:30   ` Rafael J. Wysocki
  1 sibling, 2 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-30 22:30 UTC (permalink / raw)
  To: jean.pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> Re-design the PM QoS implementation to support the per-device
> constraints:

Well, I guess I should have reviewed this patch before [03/13].

> - Define a pm_qos_constraints struct for the storage of the constraints
> list and associated values (target_value, default_value, type ...).
> 
> - Update the pm_qos_object struct with the information related to a
> PM QoS class: ptr to constraints list, notifer ptr, name ...
> 
> - Each PM QoS class statically declare objects for pm_qos_object and
> pm_qos_constraints. The only exception is the devices constraints, cf. below.
> 
> - The device constraints class is statically declaring a pm_qos_object. The
> pm_qos_constraints are per-device and so are embedded into the device struct.
> 
> - The PM QoS internal functions are updated to operate on the pm_qos_constraints
> structs for the constraints management, and on pm_qos_object for other the PM QoS
> functionality (notifiers, export as misc devices...).
> 
> - The PM QoS events notification callbacks are passing the full constraint
> request data in order for the callees to have access to it. The current use
> is for the platform low-level code to access the target device of the constraint
> 
> - User space API: the PM QoS classes -excepted PM_QOS_DEV_LATENCY- are exporting
> a MISC entry in /dev. PM_QOS_DEV_LATENCY shall export a per-device sysfs entry, this
> support is coming as a subsequent patch.
> 
> - Misc fixes to improve code readability:
>   . rename of fields names (request, list, constraints, class),

Please avoid doing renames along with functional changes.  It makes reviewing
extremely hard.

>   . simplification of the in-kernel API implementation. The main logic part is
>     now implemented in the update_target function.
> 
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  drivers/base/power/main.c |    7 +-
>  include/linux/pm.h        |    3 +-
>  include/linux/pm_qos.h    |   23 ++++-
>  kernel/pm_qos.c           |  248 +++++++++++++++++++++++++-------------------
>  4 files changed, 170 insertions(+), 111 deletions(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index dad2eb9..360c2c0 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> -	plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +	dev->power.latency_constraints.target_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.default_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.type = PM_QOS_MIN;

Perhaps add a helper doing these assignments?

>  }
>  
>  /**
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 23c85f1..35e48a3 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -28,6 +28,7 @@
>  #include <linux/wait.h>
>  #include <linux/timer.h>
>  #include <linux/completion.h>
> +#include <linux/pm_qos.h>
>  
>  /*
>   * Callbacks for platform drivers to implement.
> @@ -464,7 +465,7 @@ struct dev_pm_info {
>  	unsigned long		accounting_timestamp;
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
> -	struct plist_head	latency_constraints;
> +	struct pm_qos_constraints	latency_constraints;

Why don't you simply call it "qos"?  The data type provides the information
about what it's for now.

>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index a2e4409..d72b16b 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -6,7 +6,6 @@
>   */
>  #include <linux/plist.h>
>  #include <linux/notifier.h>
> -#include <linux/miscdevice.h>
>  
>  #define PM_QOS_RESERVED			0
>  #define PM_QOS_CPU_DMA_LATENCY		1
> @@ -22,8 +21,28 @@
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  
> +enum pm_qos_type {
> +	PM_QOS_MAX,		/* return the largest value */
> +	PM_QOS_MIN		/* return the smallest value */
> +};
> +
> +struct pm_qos_constraints {
> +	struct plist_head list;
> +	/*
> +	 * Do not change target_value to 64 bit in order to guarantee
> +	 * accesses atomicity
> +	 */

The comment doesn't belong here.  Please put it outside of the structure
definition or after the field name (or both, in which case the "inline"
one may be shorter, like "must not be 64-bit").

> +	s32 target_value;
> +	s32 default_value;
> +	enum pm_qos_type type;
> +};
> +
> +/*
> + * Struct that is pre-allocated by the caller.
> + * The handle is kept for future use (update, removal)
> + */
>  struct pm_qos_request {
> -	struct plist_node list;
> +	struct plist_node node;

Please avoid doing such things along with functional changes.

>  	int class;
>  	struct device *dev;
>  };
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 4ede3cd..7edc6d0 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -49,71 +49,81 @@
>   * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
>   * held, taken with _irqsave.  One lock to rule them all
>   */
> -enum pm_qos_type {
> -	PM_QOS_MAX,		/* return the largest value */
> -	PM_QOS_MIN		/* return the smallest value */
> +
> +enum pm_qos_req_action {
> +	PM_QOS_ADD_REQ,
> +	PM_QOS_UPDATE_REQ,
> +	PM_QOS_REMOVE_REQ
>  };

A comment describing the meaning of these would be helpful.
  
> -/*
> - * Note: The lockless read path depends on the CPU accessing
> - * target_value atomically.  Atomic access is only guaranteed on all CPU
> - * types linux supports for 32 bit quantites
> - */
>  struct pm_qos_object {
> -	struct plist_head requests;
> +	struct pm_qos_constraints *constraints;
>  	struct blocking_notifier_head *notifiers;
>  	struct miscdevice pm_qos_power_miscdev;
>  	char *name;
> -	s32 target_value;	/* Do not change to 64 bit */
> -	s32 default_value;
> -	enum pm_qos_type type;
>  };
>  
>  static DEFINE_SPINLOCK(pm_qos_lock);
>  
>  static struct pm_qos_object null_pm_qos;
> +
> +/* CPU/DMA latency constraints PM QoS object */
> +static struct pm_qos_constraints cpu_dma_constraints = {
> +	.list = PLIST_HEAD_INIT(cpu_dma_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> +	.type = PM_QOS_MIN,
> +};
>  static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
>  static struct pm_qos_object cpu_dma_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
> +	.constraints = &cpu_dma_constraints,
>  	.notifiers = &cpu_dma_lat_notifier,
>  	.name = "cpu_dma_latency",
> -	.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN,
>  };
>  
> +/*
> + * Per-device latency constraints PM QoS object
> + *
> + * The constraints are stored in the device struct data.
> + * No misc device is exported to /dev, instead the user space API
> + * shall use a per-device /sysfs entry.
> + */
>  static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
>  static struct pm_qos_object dev_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> +	.constraints = NULL,
>  	.notifiers = &dev_lat_notifier,
> +	.pm_qos_power_miscdev = { .minor = -1 },
>  	.name = "dev_latency",
> -	.target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN,
>  };
>  
> +/* Network latency constraints PM QoS object */
> +static struct pm_qos_constraints network_lat_constraints = {
> +	.list = PLIST_HEAD_INIT(network_lat_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_NETWORK_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),
> +	.constraints = &network_lat_constraints,
>  	.notifiers = &network_lat_notifier,
>  	.name = "network_latency",
> -	.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> -	.type = PM_QOS_MIN
>  };
>  
> -
> +/* Network throughput constraints PM QoS object */
> +static struct pm_qos_constraints network_tput_constraints = {
> +	.list = PLIST_HEAD_INIT(network_tput_constraints.list, pm_qos_lock),
> +	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> +	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> +	.type = PM_QOS_MAX,
> +};
>  static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
>  static struct pm_qos_object network_throughput_pm_qos = {
> -	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
> +	.constraints = &network_tput_constraints,
>  	.notifiers = &network_throughput_notifier,
>  	.name = "network_throughput",
> -	.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> -	.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> -	.type = PM_QOS_MAX,
>  };
>  
> -
>  static struct pm_qos_object *pm_qos_array[] = {
>  	&null_pm_qos,
>  	&cpu_dma_pm_qos,
> @@ -138,17 +148,17 @@ static const struct file_operations pm_qos_power_fops = {
>  };
>  
>  /* unlocked internal variant */
> -static inline int pm_qos_get_value(struct pm_qos_object *o)
> +static inline int pm_qos_get_value(struct pm_qos_constraints *c)

I'd remove the "inline" if you're at it.  It's only a hint if the kernel
is not built with "always inline" and the compiler should do the inlining
anyway if that's a better choice.

>  {
> -	if (plist_head_empty(&o->requests))
> -		return o->default_value;
> +	if (plist_head_empty(&c->list))
> +		return c->default_value;
>  
> -	switch (o->type) {
> +	switch (c->type) {
>  	case PM_QOS_MIN:
> -		return plist_first(&o->requests)->prio;
> +		return plist_first(&c->list)->prio;
>  
>  	case PM_QOS_MAX:
> -		return plist_last(&o->requests)->prio;
> +		return plist_last(&c->list)->prio;
>  
>  	default:
>  		/* runtime check for not using enum */
> @@ -156,69 +166,92 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
>  	}
>  }
>  
> -static inline s32 pm_qos_read_value(struct pm_qos_object *o)
> +/*
> + * pm_qos_read_value atomically reads and returns target_value.

We have a standard for writing kerneldoc comments, please follow it.

> + * target_value is updated upon update of the constraints list, using
> + * pm_qos_set_value.
> + *
> + * Note: The lockless read path depends on the CPU accessing
> + * target_value atomically.  Atomic access is only guaranteed on all CPU
> + * types linux supports for 32 bit quantites

You should say "data types" rather than "quantities" here.

> + */
> +static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
>  {
> -	return o->target_value;
> +	if (c)
> +		return c->target_value;
> +	else
> +		return 0;
>  }
>  
> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
>  {
> -	o->target_value = value;
> +	c->target_value = value;
>  }

Well, I'm not sure that this function is necessary at all.  You might as well
simply remove it as far as I'm concerned.

> -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 *req,
> +			  enum pm_qos_req_action action, int value)
>  {
>  	unsigned long flags;
> -	int prev_value, curr_value;
> +	int prev_value, curr_value, new_value;
> +	struct pm_qos_object *o = pm_qos_array[req->class];
> +	struct pm_qos_constraints *c;
> +
> +	switch (req->class) {
> +	case PM_QOS_DEV_LATENCY:
> +		if (!req->dev) {
> +			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
> +			return;
> +		}
> +		c = &req->dev->power.latency_constraints;
> +		break;
> +	case PM_QOS_CPU_DMA_LATENCY:
> +	case PM_QOS_NETWORK_LATENCY:
> +	case PM_QOS_NETWORK_THROUGHPUT:
> +		c = o->constraints;
> +		break;
> +	case PM_QOS_RESERVED:
> +	default:
> +		WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
> +			"req 0x%p\n", req->class, req);
> +		return;
> +	}

Do we _really_ need that switch()?

What about introducing dev_pm_qos_add_request() and friends specifically
for devices, such that they will take the target device object (dev) as
their first argument?  Then, you could keep pm_qos_add_request() pretty
much as is, right?

>  
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	prev_value = pm_qos_get_value(o);
> -	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> -	if (value != PM_QOS_DEFAULT_VALUE) {
> +
> +	prev_value = pm_qos_get_value(c);
> +	if (value == PM_QOS_DEFAULT_VALUE)
> +		new_value = c->default_value;
> +	else
> +		new_value = value;

What about writing that as

	new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;

> +
> +	switch (action) {
> +	case PM_QOS_REMOVE_REQ:
> +		plist_del(&req->node, &c->list);
> +		break;
> +	case PM_QOS_UPDATE_REQ:
>  		/*
>  		 * to change the list, we atomically remove, reinit
>  		 * with new value and add, then see if the extremal
>  		 * changed
>  		 */
> -		plist_del(node, &o->requests);
> -		plist_node_init(node, value);
> -		plist_add(node, &o->requests);
> -	} else if (del) {
> -		plist_del(node, &o->requests);
> -	} else {
> -		plist_add(node, &o->requests);
> +		plist_del(&req->node, &c->list);
> +	case PM_QOS_ADD_REQ:
> +		plist_node_init(&req->node, new_value);
> +		plist_add(&req->node, &c->list);
> +		break;
> +	default:
> +		/* no action */
> +		;
>  	}
> -	curr_value = pm_qos_get_value(o);
> -	pm_qos_set_value(o, curr_value);
> +
> +	curr_value = pm_qos_get_value(c);
> +	pm_qos_set_value(c, curr_value);
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  
>  	if (prev_value != curr_value)
>  		blocking_notifier_call_chain(o->notifiers,

That's why I'm thinking that it would be helpful to have a pointer
to the notifier list from struct pm_qos_constraints .

Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
"o->notifiers".

>  					     (unsigned long)curr_value,
> -					     NULL);
> -}
> -
> -static int register_pm_qos_misc(struct pm_qos_object *qos)
> -{
> -	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> -	qos->pm_qos_power_miscdev.name = qos->name;
> -	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> -
> -	return misc_register(&qos->pm_qos_power_miscdev);
> -}
> -
> -static int find_pm_qos_object_by_minor(int minor)
> -{
> -	int pm_qos_class;
> -
> -	for (pm_qos_class = 0;
> -		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> -		if (minor ==
> -			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> -			return pm_qos_class;
> -	}
> -	return -1;
> +					     req);
>  }
>  
>  /**
> @@ -229,7 +262,7 @@ static int find_pm_qos_object_by_minor(int minor)
>   */
>  int pm_qos_request(int class)
>  {
> -	return pm_qos_read_value(pm_qos_array[class]);
> +	return pm_qos_read_value(pm_qos_array[class]->constraints);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_request);
>  
> @@ -254,22 +287,15 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
>  void pm_qos_add_request(struct pm_qos_request *req,
>  			struct pm_qos_parameters *params)
>  {
> -	struct pm_qos_object *o =  pm_qos_array[params->class];
> -	int new_value;
> -
>  	if (pm_qos_request_active(req)) {
>  		WARN(1, KERN_ERR "pm_qos_add_request() called for already "
>  			"added request\n");
>  		return;
>  	}
> -	if (params->value == PM_QOS_DEFAULT_VALUE)
> -		new_value = o->default_value;
> -	else
> -		new_value = params->value;
> -	plist_node_init(&req->list, new_value);
> +
>  	req->class = params->class;
>  	req->dev = params->dev;
> -	update_target(o, &req->list, 0, PM_QOS_DEFAULT_VALUE);
> +	update_target(req, PM_QOS_ADD_REQ, params->value);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_add_request);
>  
> @@ -285,9 +311,6 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
>   */
>  void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  {
> -	s32 temp;
> -	struct pm_qos_object *o;
> -
>  	if (!req) /*guard against callers passing in null */
>  		return;
>  
> @@ -296,15 +319,8 @@ void pm_qos_update_request(struct pm_qos_request *req, s32 new_value)
>  		return;
>  	}
>  
> -	o = pm_qos_array[req->class];
> -
> -	if (new_value == PM_QOS_DEFAULT_VALUE)
> -		temp = o->default_value;
> -	else
> -		temp = new_value;
> -
> -	if (temp != req->list.prio)
> -		update_target(o, &req->list, 0, temp);
> +	if (new_value != req->node.prio)
> +		update_target(req, PM_QOS_UPDATE_REQ, new_value);
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_update_request);
>  
> @@ -318,8 +334,6 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
>   */
>  void pm_qos_remove_request(struct pm_qos_request *req)
>  {
> -	struct pm_qos_object *o;
> -
>  	if (req == NULL)
>  		return;
>  		/* silent return to keep pcm code cleaner */
> @@ -329,8 +343,8 @@ void pm_qos_remove_request(struct pm_qos_request *req)
>  		return;
>  	}
>  
> -	o = pm_qos_array[req->class];
> -	update_target(o, &req->list, 1, PM_QOS_DEFAULT_VALUE);
> +	update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
> +
>  	memset(req, 0, sizeof(*req));
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_request);
> @@ -373,6 +387,28 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
>  
> +static int register_pm_qos_misc(struct pm_qos_object *qos)
> +{
> +	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> +	qos->pm_qos_power_miscdev.name = qos->name;
> +	qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> +
> +	return misc_register(&qos->pm_qos_power_miscdev);
> +}
> +
> +static int find_pm_qos_object_by_minor(int minor)
> +{
> +	int pm_qos_class;
> +
> +	for (pm_qos_class = 0;
> +		pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> +		if (minor ==
> +			pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> +			return pm_qos_class;
> +	}
> +	return -1;
> +}

This function doesn't seem to be used anywhere, what's the purpose of it?

> +
>  static int pm_qos_power_open(struct inode *inode, struct file *filp)
>  {
>  	struct pm_qos_parameters pm_qos_params;
> @@ -410,7 +446,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
>  {
>  	s32 value;
>  	unsigned long flags;
> -	struct pm_qos_object *o;
>  	struct pm_qos_request *req = filp->private_data;
>  
>  	if (!req)
> @@ -418,9 +453,8 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
>  	if (!pm_qos_request_active(req))
>  		return -EINVAL;
>  
> -	o = pm_qos_array[req->class];
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	value = pm_qos_get_value(o);
> +	value = pm_qos_get_value(pm_qos_array[req->class]->constraints);
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  
>  	return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));

Thanks,
Rafael

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

* Re: [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-28  8:30 ` jean.pihet
@ 2011-07-30 22:38   ` Rafael J. Wysocki
  2011-07-30 22:38   ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-30 22:38 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> The devices latency constraints class of PM QoS is storing the
> constraints list in the device dev_pm_info struct.
> 
> This patch adds the init and de-init of the per-device constraints
> list in order to support the dynamic insertion and removal
> of the devices in the system.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  drivers/base/power/main.c |   10 ++++------
>  include/linux/pm.h        |    1 +
>  include/linux/pm_qos.h    |    2 ++
>  kernel/pm_qos.c           |   30 ++++++++++++++++++++++++++++++
>  4 files changed, 37 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 360c2c0..c86f97c 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,12 +97,8 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> -	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> -	dev->power.latency_constraints.target_value =
> -					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> -	dev->power.latency_constraints.default_value =
> -					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> -	dev->power.latency_constraints.type = PM_QOS_MIN;
> +	/* Call PM QoS to init the per-device latency constraints */
> +	pm_qos_dev_constraints_init(dev);
>  }
>  
>  /**
> @@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
>  {
>  	pr_debug("PM: Removing info for %s:%s\n",
>  		 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
> +	/* Call PM QoS to de-init the per-device latency constraints */
> +	pm_qos_dev_constraints_deinit(dev);

I'd call this function "dev_pm_qos_constraints_destroy()" (and the previous
one "dev_pm_qos_constraints_init()" for consistency).

>  	complete_all(&dev->power.completion);
>  	mutex_lock(&dpm_list_mtx);
>  	list_del_init(&dev->power.entry);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 35e48a3..3ed53be 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -466,6 +466,7 @@ struct dev_pm_info {
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
>  	struct pm_qos_constraints	latency_constraints;
> +	int			latency_constraints_init;
>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index d72b16b..4d36537 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -63,4 +63,6 @@ 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 *req);
>  
> +void pm_qos_dev_constraints_init(struct device *dev);
> +void pm_qos_dev_constraints_deinit(struct device *dev);
>  #endif
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 7edc6d0..361fc3f 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -202,6 +202,9 @@ static void update_target(struct pm_qos_request *req,
>  			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
>  			return;
>  		}
> +		/* Silently return if the device is being released */
> +		if (!req->dev->power.latency_constraints_init)
> +			return;
>  		c = &req->dev->power.latency_constraints;
>  		break;
>  	case PM_QOS_CPU_DMA_LATENCY:
> @@ -387,6 +390,33 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
>  
> +/* Called from the device PM subsystem at device init */
> +void pm_qos_dev_constraints_init(struct device *dev)
> +{
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +	dev->power.latency_constraints.target_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.default_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.type = PM_QOS_MIN;
> +	dev->power.latency_constraints_init = 1;

You could avoid adding this field if there were a PM_QOS_UNINITIALIZED
(or PM_QOS_UNKNOWN) type.

And if you _really_ want to have a separate field, why don't you put it
into latency_constraints ?

> +}
> +
> +/* Called from the device PM subsystem at device release */
> +void pm_qos_dev_constraints_deinit(struct device *dev)
> +{
> +	struct pm_qos_request *req, *tmp;
> +
> +	dev->power.latency_constraints_init = 0;
> +
> +	/* Flush the constraints list for the device */
> +	plist_for_each_entry_safe(req, tmp,
> +				  &dev->power.latency_constraints.list,
> +				  node)
> +		update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +}
> +
>  static int register_pm_qos_misc(struct pm_qos_object *qos)
>  {
>  	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> 

Thanks,
Rafael

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

* Re: [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-28  8:30 ` jean.pihet
  2011-07-30 22:38   ` Rafael J. Wysocki
@ 2011-07-30 22:38   ` Rafael J. Wysocki
  2011-08-02 10:07     ` Jean Pihet
  2011-08-02 10:07     ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-07-30 22:38 UTC (permalink / raw)
  To: jean.pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
> 
> The devices latency constraints class of PM QoS is storing the
> constraints list in the device dev_pm_info struct.
> 
> This patch adds the init and de-init of the per-device constraints
> list in order to support the dynamic insertion and removal
> of the devices in the system.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  drivers/base/power/main.c |   10 ++++------
>  include/linux/pm.h        |    1 +
>  include/linux/pm_qos.h    |    2 ++
>  kernel/pm_qos.c           |   30 ++++++++++++++++++++++++++++++
>  4 files changed, 37 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 360c2c0..c86f97c 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -97,12 +97,8 @@ void device_pm_add(struct device *dev)
>  			dev_name(dev->parent));
>  	list_add_tail(&dev->power.entry, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> -	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> -	dev->power.latency_constraints.target_value =
> -					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> -	dev->power.latency_constraints.default_value =
> -					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> -	dev->power.latency_constraints.type = PM_QOS_MIN;
> +	/* Call PM QoS to init the per-device latency constraints */
> +	pm_qos_dev_constraints_init(dev);
>  }
>  
>  /**
> @@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
>  {
>  	pr_debug("PM: Removing info for %s:%s\n",
>  		 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
> +	/* Call PM QoS to de-init the per-device latency constraints */
> +	pm_qos_dev_constraints_deinit(dev);

I'd call this function "dev_pm_qos_constraints_destroy()" (and the previous
one "dev_pm_qos_constraints_init()" for consistency).

>  	complete_all(&dev->power.completion);
>  	mutex_lock(&dpm_list_mtx);
>  	list_del_init(&dev->power.entry);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 35e48a3..3ed53be 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -466,6 +466,7 @@ struct dev_pm_info {
>  	void			*subsys_data;  /* Owned by the subsystem. */
>  #endif
>  	struct pm_qos_constraints	latency_constraints;
> +	int			latency_constraints_init;
>  };
>  
>  extern void update_pm_runtime_accounting(struct device *dev);
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index d72b16b..4d36537 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -63,4 +63,6 @@ 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 *req);
>  
> +void pm_qos_dev_constraints_init(struct device *dev);
> +void pm_qos_dev_constraints_deinit(struct device *dev);
>  #endif
> diff --git a/kernel/pm_qos.c b/kernel/pm_qos.c
> index 7edc6d0..361fc3f 100644
> --- a/kernel/pm_qos.c
> +++ b/kernel/pm_qos.c
> @@ -202,6 +202,9 @@ static void update_target(struct pm_qos_request *req,
>  			WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
>  			return;
>  		}
> +		/* Silently return if the device is being released */
> +		if (!req->dev->power.latency_constraints_init)
> +			return;
>  		c = &req->dev->power.latency_constraints;
>  		break;
>  	case PM_QOS_CPU_DMA_LATENCY:
> @@ -387,6 +390,33 @@ int pm_qos_remove_notifier(int class, struct notifier_block *notifier)
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
>  
> +/* Called from the device PM subsystem at device init */
> +void pm_qos_dev_constraints_init(struct device *dev)
> +{
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +	dev->power.latency_constraints.target_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.default_value =
> +					PM_QOS_DEV_LAT_DEFAULT_VALUE;
> +	dev->power.latency_constraints.type = PM_QOS_MIN;
> +	dev->power.latency_constraints_init = 1;

You could avoid adding this field if there were a PM_QOS_UNINITIALIZED
(or PM_QOS_UNKNOWN) type.

And if you _really_ want to have a separate field, why don't you put it
into latency_constraints ?

> +}
> +
> +/* Called from the device PM subsystem at device release */
> +void pm_qos_dev_constraints_deinit(struct device *dev)
> +{
> +	struct pm_qos_request *req, *tmp;
> +
> +	dev->power.latency_constraints_init = 0;
> +
> +	/* Flush the constraints list for the device */
> +	plist_for_each_entry_safe(req, tmp,
> +				  &dev->power.latency_constraints.list,
> +				  node)
> +		update_target(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
> +	plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
> +}
> +
>  static int register_pm_qos_misc(struct pm_qos_object *qos)
>  {
>  	qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> 

Thanks,
Rafael

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

* Re: [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29 21:46       ` Rafael J. Wysocki
@ 2011-07-31 17:38         ` mark gross
  2011-07-31 17:38         ` [linux-pm] " mark gross
  1 sibling, 0 replies; 78+ messages in thread
From: mark gross @ 2011-07-31 17:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM mailing list, broonie, Jean Pihet, linux-omap, markgross

On Fri, Jul 29, 2011 at 11:46:21PM +0200, Rafael J. Wysocki wrote:
> On Friday, July 29, 2011, mark gross wrote:
> > On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> > > Mark,
> > > 
> > > On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > > > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> > > >>
> > > >> High level implementation:
> > > >>
> > > ...
> > > 
> > > >> 7. Misc fixes to improve code readability:
> > > >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > > > I picked the name for the file as pm_qos_params over pm_qos because I
> > > > wanted to make it implicitly clear that this was not an full QOS
> > > > implementation.  True QOS carries expectations similar to real time and
> > > > as the infrastructure is closer to "good intentioned" than even "best
> > > > effort" and offers no notification when the QOS request is not able to
> > > > be met and really doesn't implement a true QOS at all, (it just provides
> > > > the parameter interface for part of one its missing the notification
> > > > interface when the service level is not met and I think a few other
> > > > things.) So I wanted to have it named a bit different from just pm_qos.
> > > >
> > > > This said I'm not supper attached to the naming of the modules.  If
> > > > folks want to change it I wouldn't complain (too much anyway;).
> > > Ok got the idea. I do not know what name to chose though. As suggested
> > > previously the name pm_qos_params does not reflect the implementation,
> > > that is why I renamed it.
> > 
> > I must have missed the part where the name doesn't reflect the
> > implementation was talked about.  I look at the interface and I see
> > parameters all over the place and a small bit of notification.
> 
> The interface is for specifying PM QoS requirements or constraints that
> may or may not be regarded as "parameters", depending on ones definition
> of the last term.  Moreover, the code not only implements the interface,
> but also defines data structures and API to be used throughout the kernel
> which is quite a bit more than just "parameters".
> 
> In my not so humble opinion the name isn't good and the .c file should be
> in kernel/power in the first place.  I would call it simply qos.c (the fact
> that _right_ _now_ it's not a full QoS implementation doesn't matter, because
> it may become one in the future).

Sounds ok to me.

--mark

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

* Re: [linux-pm] [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class
  2011-07-29 21:46       ` Rafael J. Wysocki
  2011-07-31 17:38         ` mark gross
@ 2011-07-31 17:38         ` mark gross
  1 sibling, 0 replies; 78+ messages in thread
From: mark gross @ 2011-07-31 17:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Fri, Jul 29, 2011 at 11:46:21PM +0200, Rafael J. Wysocki wrote:
> On Friday, July 29, 2011, mark gross wrote:
> > On Fri, Jul 29, 2011 at 10:37:52AM +0200, Jean Pihet wrote:
> > > Mark,
> > > 
> > > On Thu, Jul 28, 2011 at 3:14 PM, mark gross <markgross@thegnar.org> wrote:
> > > > On Thu, Jul 28, 2011 at 10:30:07AM +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.
> > > >>
> > > >> High level implementation:
> > > >>
> > > ...
> > > 
> > > >> 7. Misc fixes to improve code readability:
> > > >> . rename of the PM QoS implementation file from pm_qos_params.[ch] to pm_qos.[ch]
> > > > I picked the name for the file as pm_qos_params over pm_qos because I
> > > > wanted to make it implicitly clear that this was not an full QOS
> > > > implementation.  True QOS carries expectations similar to real time and
> > > > as the infrastructure is closer to "good intentioned" than even "best
> > > > effort" and offers no notification when the QOS request is not able to
> > > > be met and really doesn't implement a true QOS at all, (it just provides
> > > > the parameter interface for part of one its missing the notification
> > > > interface when the service level is not met and I think a few other
> > > > things.) So I wanted to have it named a bit different from just pm_qos.
> > > >
> > > > This said I'm not supper attached to the naming of the modules.  If
> > > > folks want to change it I wouldn't complain (too much anyway;).
> > > Ok got the idea. I do not know what name to chose though. As suggested
> > > previously the name pm_qos_params does not reflect the implementation,
> > > that is why I renamed it.
> > 
> > I must have missed the part where the name doesn't reflect the
> > implementation was talked about.  I look at the interface and I see
> > parameters all over the place and a small bit of notification.
> 
> The interface is for specifying PM QoS requirements or constraints that
> may or may not be regarded as "parameters", depending on ones definition
> of the last term.  Moreover, the code not only implements the interface,
> but also defines data structures and API to be used throughout the kernel
> which is quite a bit more than just "parameters".
> 
> In my not so humble opinion the name isn't good and the .c file should be
> in kernel/power in the first place.  I would call it simply qos.c (the fact
> that _right_ _now_ it's not a full QoS implementation doesn't matter, because
> it may become one in the future).

Sounds ok to me.

--mark

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-29  8:50     ` Jean Pihet
@ 2011-08-02  8:57       ` Jean Pihet
  2011-08-02  8:57       ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02  8:57 UTC (permalink / raw)
  To: Todd Poynor
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Todd,

On Fri, Jul 29, 2011 at 10:50 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
>> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
...

>>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>>> index 9af0847..63c3e7a 100644
>>> --- a/arch/arm/mach-omap2/powerdomain.c
>>> +++ b/arch/arm/mach-omap2/powerdomain.c
>>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>>       pwrdm->state_counter[pwrdm->state] = 1;
>>>
>>> +     /* Early init of the next power state */
>>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>>> +
>>
>> Wanted to check that it's OK to initialize the next state of a power
>> domain to RETENTION early in the boot sequence.  I believe patches
>> have been previously discussed that set the state to ON to ensure the
>> domain doesn't go to a lower state, and possibly lose context, before
>> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
>> a doublecheck.
> Indeed I need to check the behavior for OMAP3 & 4 which seem to
> initialize the pwrdm states differently.
> BTW the patch that inits all pwrdms to ON is not yet in l-o master
> that is why I (lazily) submitted this one for now.

Ok I will update the patch to make it compliant with [1]. v4 will
include this change.

Thanks,
Jean

[1] http://marc.info/?l=linux-arm-kernel&m=131052762623823&w=2

>
>>
>>
>> Todd

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-07-29  8:50     ` Jean Pihet
  2011-08-02  8:57       ` Jean Pihet
@ 2011-08-02  8:57       ` Jean Pihet
  2011-08-11 15:12         ` Jean Pihet
  2011-08-11 15:12         ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02  8:57 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet, rnayak

Todd,

On Fri, Jul 29, 2011 at 10:50 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
>> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
...

>>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>>> index 9af0847..63c3e7a 100644
>>> --- a/arch/arm/mach-omap2/powerdomain.c
>>> +++ b/arch/arm/mach-omap2/powerdomain.c
>>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>>       pwrdm->state_counter[pwrdm->state] = 1;
>>>
>>> +     /* Early init of the next power state */
>>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>>> +
>>
>> Wanted to check that it's OK to initialize the next state of a power
>> domain to RETENTION early in the boot sequence.  I believe patches
>> have been previously discussed that set the state to ON to ensure the
>> domain doesn't go to a lower state, and possibly lose context, before
>> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
>> a doublecheck.
> Indeed I need to check the behavior for OMAP3 & 4 which seem to
> initialize the pwrdm states differently.
> BTW the patch that inits all pwrdms to ON is not yet in l-o master
> that is why I (lazily) submitted this one for now.

Ok I will update the patch to make it compliant with [1]. v4 will
include this change.

Thanks,
Jean

[1] http://marc.info/?l=linux-arm-kernel&m=131052762623823&w=2

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

* Re: [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-07-29 21:57   ` Rafael J. Wysocki
@ 2011-08-02  9:31     ` Jean Pihet
  2011-08-02  9:47       ` Rafael J. Wysocki
  2011-08-02  9:47       ` Rafael J. Wysocki
  0 siblings, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02  9:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Rafael,

2011/7/29 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> The PM QoS implementation files are better named
>> kernel/pm_qos.c and include/linux/pm_qos.h.
>>
...

>>  create mode 100644 include/linux/pm_qos.h
>>  delete mode 100644 include/linux/pm_qos_params.h
>
> That I agree with.
>
>>  create mode 100644 kernel/pm_qos.c
>>  delete mode 100644 kernel/pm_qos_params.c
>
> As I said, please move that file to kernel/power and call it qos.c.
Ok

>
> That said the device interface should be located in drivers/base/power
> to follow our current conventions.
By device interface I understand the following:
- the user space API (per-device sysfs entry),
- the in-kernel device specific PM QoS API. If needed, cf. comments on
[04/13] about that.

Is that correct?

>
> Thanks,
> Rafael

Thanks,
Jean

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-29 22:55   ` Rafael J. Wysocki
  2011-08-02  9:41     ` Jean Pihet
@ 2011-08-02  9:41     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02  9:41 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Rafael,

2011/7/30 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> Extend the PM QoS kernel API:
>> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
>> constraints
>> - make the pm_qos_add_request API more generic by using a parameter of
>> type struct pm_qos_parameters
>> - minor clean-ups and rename of struct fields:
>>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>>   . consistenly use req and params as the API parameters
>>   . rename struct pm_qos_request_list to struct pm_qos_request
>> - update the in-kernel API callers to the new API
>
> There should be more about the motivation in the changelog.  It says
> what the patch is doing, but it doesn't say a word of _why_ it is done in
> the first place.
Ok will add a comment

>
> Second, you're renaming a lot of things in the same patch that makes
> functional changes.  This is confusing and makes it very difficult to
> understand what's going on.  Please use separate patches to rename
> things, when possible, and avoid renaming things that don't need to be
> renamed.
Sorry about that! I will split up the patches.

...
>>
>> -struct pm_qos_request_list {
>> +struct pm_qos_request {
>
> This renaming should go in a separate patch, really.
Ok

>
>>       struct plist_node list;
>> -     int pm_qos_class;
>> +     int class;
>
> This renaming doesn't seem to be necessary.  Moreover, it's confusing,
> because there already is struct class (for device classes) and a member
> called "class" in struct device and they aren't related to this one.
I will keep pm_qos_class if the rename brings in some confusion. The
intention was to simplify the names of the fields in structs with
explicit names.

>
>> +     struct device *dev;
>>  };
>>
>> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
>> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
>> -             s32 new_value);
>> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
>> +struct pm_qos_parameters {
>> +     int class;
>> +     struct device *dev;
>> +     s32 value;
>> +};
>
> What exactly is the "dev" member needed for?
This is the target device that is passed as parameter to the API. It
is used for constraints of the devices latency class.

...
>> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
>> +static struct pm_qos_object dev_pm_qos = {
>> +     .requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
>> +     .notifiers = &dev_lat_notifier,
>> +     .name = "dev_latency",
>> +     .target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
>> +     .default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
>> +     .type = PM_QOS_MIN,
>> +};
>> +
>
> You seem to be confusing things here.  Since devices will have their own lists
> of requests now (as per the previous patch), the .requests member above is not
> necessary.  Moreover, it seems to be used incorrectly below.
The idea was to split the patches as requested previously: first the
API changes (this very patch [03/13]) and then the actual
implementation ([04/13]). Is this correct?

...
>> -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);
>
> Now, there's a question if we want to have one notifier chain for all
> devices or if it's better to have a per-device notifier chain.  Both
> approaches have their own advantages and drawbacks, but in the latter
> case this code will have to be reworked.
I really think the need is for a per-class notifier. Cf. comments on
[04/13] about that.

>
> Thanks,
> Rafael

Thanks,
Jean

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-29 22:55   ` Rafael J. Wysocki
@ 2011-08-02  9:41     ` Jean Pihet
  2011-08-02 21:02       ` Rafael J. Wysocki
  2011-08-02 21:02       ` Rafael J. Wysocki
  2011-08-02  9:41     ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02  9:41 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

Rafael,

2011/7/30 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> Extend the PM QoS kernel API:
>> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
>> constraints
>> - make the pm_qos_add_request API more generic by using a parameter of
>> type struct pm_qos_parameters
>> - minor clean-ups and rename of struct fields:
>>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>>   . consistenly use req and params as the API parameters
>>   . rename struct pm_qos_request_list to struct pm_qos_request
>> - update the in-kernel API callers to the new API
>
> There should be more about the motivation in the changelog.  It says
> what the patch is doing, but it doesn't say a word of _why_ it is done in
> the first place.
Ok will add a comment

>
> Second, you're renaming a lot of things in the same patch that makes
> functional changes.  This is confusing and makes it very difficult to
> understand what's going on.  Please use separate patches to rename
> things, when possible, and avoid renaming things that don't need to be
> renamed.
Sorry about that! I will split up the patches.

...
>>
>> -struct pm_qos_request_list {
>> +struct pm_qos_request {
>
> This renaming should go in a separate patch, really.
Ok

>
>>       struct plist_node list;
>> -     int pm_qos_class;
>> +     int class;
>
> This renaming doesn't seem to be necessary.  Moreover, it's confusing,
> because there already is struct class (for device classes) and a member
> called "class" in struct device and they aren't related to this one.
I will keep pm_qos_class if the rename brings in some confusion. The
intention was to simplify the names of the fields in structs with
explicit names.

>
>> +     struct device *dev;
>>  };
>>
>> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
>> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
>> -             s32 new_value);
>> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
>> +struct pm_qos_parameters {
>> +     int class;
>> +     struct device *dev;
>> +     s32 value;
>> +};
>
> What exactly is the "dev" member needed for?
This is the target device that is passed as parameter to the API. It
is used for constraints of the devices latency class.

...
>> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
>> +static struct pm_qos_object dev_pm_qos = {
>> +     .requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
>> +     .notifiers = &dev_lat_notifier,
>> +     .name = "dev_latency",
>> +     .target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
>> +     .default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
>> +     .type = PM_QOS_MIN,
>> +};
>> +
>
> You seem to be confusing things here.  Since devices will have their own lists
> of requests now (as per the previous patch), the .requests member above is not
> necessary.  Moreover, it seems to be used incorrectly below.
The idea was to split the patches as requested previously: first the
API changes (this very patch [03/13]) and then the actual
implementation ([04/13]). Is this correct?

...
>> -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);
>
> Now, there's a question if we want to have one notifier chain for all
> devices or if it's better to have a per-device notifier chain.  Both
> approaches have their own advantages and drawbacks, but in the latter
> case this code will have to be reworked.
I really think the need is for a per-class notifier. Cf. comments on
[04/13] about that.

>
> Thanks,
> Rafael

Thanks,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-08-02  9:31     ` Jean Pihet
  2011-08-02  9:47       ` Rafael J. Wysocki
@ 2011-08-02  9:47       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02  9:47 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

On Tuesday, August 02, 2011, Jean Pihet wrote:
> Rafael,
> 
> 2011/7/29 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> >> From: Jean Pihet <j-pihet@ti.com>
> >>
> >> The PM QoS implementation files are better named
> >> kernel/pm_qos.c and include/linux/pm_qos.h.
> >>
> ...
> 
> >>  create mode 100644 include/linux/pm_qos.h
> >>  delete mode 100644 include/linux/pm_qos_params.h
> >
> > That I agree with.
> >
> >>  create mode 100644 kernel/pm_qos.c
> >>  delete mode 100644 kernel/pm_qos_params.c
> >
> > As I said, please move that file to kernel/power and call it qos.c.
> Ok
> 
> >
> > That said the device interface should be located in drivers/base/power
> > to follow our current conventions.
> By device interface I understand the following:
> - the user space API (per-device sysfs entry),
> - the in-kernel device specific PM QoS API. If needed, cf. comments on
> [04/13] about that.
> 
> Is that correct?

Yes, it is.

I think that the definitions of the dev_pm_qos_*() funtions mentioned
in there may go into drivers/base/power/qos.c and they can call functions
from kernel/power/qos.c.

Thanks,
Rafael

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

* Re: [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos
  2011-08-02  9:31     ` Jean Pihet
@ 2011-08-02  9:47       ` Rafael J. Wysocki
  2011-08-02  9:47       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02  9:47 UTC (permalink / raw)
  To: Jean Pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

On Tuesday, August 02, 2011, Jean Pihet wrote:
> Rafael,
> 
> 2011/7/29 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
> >> From: Jean Pihet <j-pihet@ti.com>
> >>
> >> The PM QoS implementation files are better named
> >> kernel/pm_qos.c and include/linux/pm_qos.h.
> >>
> ...
> 
> >>  create mode 100644 include/linux/pm_qos.h
> >>  delete mode 100644 include/linux/pm_qos_params.h
> >
> > That I agree with.
> >
> >>  create mode 100644 kernel/pm_qos.c
> >>  delete mode 100644 kernel/pm_qos_params.c
> >
> > As I said, please move that file to kernel/power and call it qos.c.
> Ok
> 
> >
> > That said the device interface should be located in drivers/base/power
> > to follow our current conventions.
> By device interface I understand the following:
> - the user space API (per-device sysfs entry),
> - the in-kernel device specific PM QoS API. If needed, cf. comments on
> [04/13] about that.
> 
> Is that correct?

Yes, it is.

I think that the definitions of the dev_pm_qos_*() funtions mentioned
in there may go into drivers/base/power/qos.c and they can call functions
from kernel/power/qos.c.

Thanks,
Rafael

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-30 22:30   ` Rafael J. Wysocki
  2011-08-02 10:05     ` Jean Pihet
@ 2011-08-02 10:05     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02 10:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Rafael,

2011/7/31 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> Re-design the PM QoS implementation to support the per-device
>> constraints:
>
> Well, I guess I should have reviewed this patch before [03/13].
Hmm indeed. The split of patches into API and implementation patches
wakes it rather confusing. I could add a comment in [03/13] about it.

...

>> - Misc fixes to improve code readability:
>>   . rename of fields names (request, list, constraints, class),
>
> Please avoid doing renames along with functional changes.  It makes reviewing
> extremely hard.
Ok I will move the renames in a different patch.

...
>> @@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
>>                       dev_name(dev->parent));
>>       list_add_tail(&dev->power.entry, &dpm_list);
>>       mutex_unlock(&dpm_list_mtx);
>> -     plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
>> +     plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
>> +     dev->power.latency_constraints.target_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.default_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.type = PM_QOS_MIN;
>
> Perhaps add a helper doing these assignments?
This code is later moved into the device insertion and removal
functions. Cf. [05/13].

...
>> @@ -464,7 +465,7 @@ struct dev_pm_info {
>>       unsigned long           accounting_timestamp;
>>       void                    *subsys_data;  /* Owned by the subsystem. */
>>  #endif
>> -     struct plist_head       latency_constraints;
>> +     struct pm_qos_constraints       latency_constraints;
>
> Why don't you simply call it "qos"?  The data type provides the information
> about what it's for now.
Ok

...
>> +struct pm_qos_constraints {
>> +     struct plist_head list;
>> +     /*
>> +      * Do not change target_value to 64 bit in order to guarantee
>> +      * accesses atomicity
>> +      */
>
> The comment doesn't belong here.  Please put it outside of the structure
> definition or after the field name (or both, in which case the "inline"
> one may be shorter, like "must not be 64-bit").
Ok

>
>> +     s32 target_value;
>> +     s32 default_value;
>> +     enum pm_qos_type type;
>> +};
>> +
>> +/*
>> + * Struct that is pre-allocated by the caller.
>> + * The handle is kept for future use (update, removal)
>> + */
>>  struct pm_qos_request {
>> -     struct plist_node list;
>> +     struct plist_node node;
>
> Please avoid doing such things along with functional changes.
Ok

...
>> +enum pm_qos_req_action {
>> +     PM_QOS_ADD_REQ,
>> +     PM_QOS_UPDATE_REQ,
>> +     PM_QOS_REMOVE_REQ
>>  };
>
> A comment describing the meaning of these would be helpful.
Ok

...
>> -static inline int pm_qos_get_value(struct pm_qos_object *o)
>> +static inline int pm_qos_get_value(struct pm_qos_constraints *c)
>
> I'd remove the "inline" if you're at it.  It's only a hint if the kernel
> is not built with "always inline" and the compiler should do the inlining
> anyway if that's a better choice.
Ok

...
>> -static inline s32 pm_qos_read_value(struct pm_qos_object *o)
>> +/*
>> + * pm_qos_read_value atomically reads and returns target_value.
>
> We have a standard for writing kerneldoc comments, please follow it.
Ok

>
>> + * target_value is updated upon update of the constraints list, using
>> + * pm_qos_set_value.
>> + *
>> + * Note: The lockless read path depends on the CPU accessing
>> + * target_value atomically.  Atomic access is only guaranteed on all CPU
>> + * types linux supports for 32 bit quantites
>
> You should say "data types" rather than "quantities" here.
Ok

>
>> + */
>> +static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
>>  {
>> -     return o->target_value;
>> +     if (c)
>> +             return c->target_value;
>> +     else
>> +             return 0;
>>  }
>>
>> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
>> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
>>  {
>> -     o->target_value = value;
>> +     c->target_value = value;
>>  }
>
> Well, I'm not sure that this function is necessary at all.  You might as well
> simply remove it as far as I'm concerned.
The idea is to provide an efficient and lockless way to get the
aggregated constraint class value. When the constraints a re changing
the new value is calculated and stored using pm_qos_get_value and
pm_qos_set_value. Then pm_qos_read_value is used to retrieve the
value. For example cpuidle calls pm_qos_request which uses
pm_qos_read_value to get the CPU/DMA minimum latency.

>
>> -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 *req,
>> +                       enum pm_qos_req_action action, int value)
>>  {
>>       unsigned long flags;
>> -     int prev_value, curr_value;
>> +     int prev_value, curr_value, new_value;
>> +     struct pm_qos_object *o = pm_qos_array[req->class];
>> +     struct pm_qos_constraints *c;
>> +
>> +     switch (req->class) {
>> +     case PM_QOS_DEV_LATENCY:
>> +             if (!req->dev) {
>> +                     WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
>> +                     return;
>> +             }
>> +             c = &req->dev->power.latency_constraints;
>> +             break;
>> +     case PM_QOS_CPU_DMA_LATENCY:
>> +     case PM_QOS_NETWORK_LATENCY:
>> +     case PM_QOS_NETWORK_THROUGHPUT:
>> +             c = o->constraints;
>> +             break;
>> +     case PM_QOS_RESERVED:
>> +     default:
>> +             WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
>> +                     "req 0x%p\n", req->class, req);
>> +             return;
>> +     }
>
> Do we _really_ need that switch()?
>
> What about introducing dev_pm_qos_add_request() and friends specifically
> for devices, such that they will take the target device object (dev) as
> their first argument?  Then, you could keep pm_qos_add_request() pretty
> much as is, right?
Yes but in that case I need to duplicate the API functions for devices
(add, update, remove). Those functions will call update_target.
I prefer the way this patch does it: simplify the API functions and
have only 1 place with the constraints management and notification
logic (in update_target).

>
>>
>>       spin_lock_irqsave(&pm_qos_lock, flags);
>> -     prev_value = pm_qos_get_value(o);
>> -     /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
>> -     if (value != PM_QOS_DEFAULT_VALUE) {
>> +
>> +     prev_value = pm_qos_get_value(c);
>> +     if (value == PM_QOS_DEFAULT_VALUE)
>> +             new_value = c->default_value;
>> +     else
>> +             new_value = value;
>
> What about writing that as
>
>        new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;
This is shorter but more difficult to read ;8

>
>> +
>> +     switch (action) {
>> +     case PM_QOS_REMOVE_REQ:
>> +             plist_del(&req->node, &c->list);
>> +             break;
>> +     case PM_QOS_UPDATE_REQ:
>>               /*
>>                * to change the list, we atomically remove, reinit
>>                * with new value and add, then see if the extremal
>>                * changed
>>                */
>> -             plist_del(node, &o->requests);
>> -             plist_node_init(node, value);
>> -             plist_add(node, &o->requests);
>> -     } else if (del) {
>> -             plist_del(node, &o->requests);
>> -     } else {
>> -             plist_add(node, &o->requests);
>> +             plist_del(&req->node, &c->list);
>> +     case PM_QOS_ADD_REQ:
>> +             plist_node_init(&req->node, new_value);
>> +             plist_add(&req->node, &c->list);
>> +             break;
>> +     default:
>> +             /* no action */
>> +             ;
>>       }
>> -     curr_value = pm_qos_get_value(o);
>> -     pm_qos_set_value(o, curr_value);
>> +
>> +     curr_value = pm_qos_get_value(c);
>> +     pm_qos_set_value(c, curr_value);
>>       spin_unlock_irqrestore(&pm_qos_lock, flags);
>>
>>       if (prev_value != curr_value)
>>               blocking_notifier_call_chain(o->notifiers,
>
> That's why I'm thinking that it would be helpful to have a pointer
> to the notifier list from struct pm_qos_constraints .
I think having a per-device notifier list is complicating things. If a
subsystem needs te be notified it needs to register a notifier
callback for _every_ device in the system.
As a first implementation for OMAP the low-level PM code is using a
single notifier to retrieve all the devices latency constraints and
apply them to the pwer domains. I do not see how this could work with
a per-device notifier list.

>
> Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
> "o->notifiers".
Ok

...
>> +static int find_pm_qos_object_by_minor(int minor)
>> +{
>> +     int pm_qos_class;
>> +
>> +     for (pm_qos_class = 0;
>> +             pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
>> +             if (minor ==
>> +                     pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
>> +                     return pm_qos_class;
>> +     }
>> +     return -1;
>> +}
>
> This function doesn't seem to be used anywhere, what's the purpose of it?
It is used by pm_qos_power_open in order to retrieve the class
associated with the MISC device.
BTW this patch is moving the code so that all the MISC related
functions are grouped together.

>
>> +
>>  static int pm_qos_power_open(struct inode *inode, struct file *filp)
>>  {
>>       struct pm_qos_parameters pm_qos_params;
...
>
> Thanks,
> Rafael

Thanks,
Jean

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-07-30 22:30   ` Rafael J. Wysocki
@ 2011-08-02 10:05     ` Jean Pihet
  2011-08-02 21:13       ` Rafael J. Wysocki
  2011-08-02 21:13       ` Rafael J. Wysocki
  2011-08-02 10:05     ` Jean Pihet
  1 sibling, 2 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02 10:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

Rafael,

2011/7/31 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> Re-design the PM QoS implementation to support the per-device
>> constraints:
>
> Well, I guess I should have reviewed this patch before [03/13].
Hmm indeed. The split of patches into API and implementation patches
wakes it rather confusing. I could add a comment in [03/13] about it.

...

>> - Misc fixes to improve code readability:
>>   . rename of fields names (request, list, constraints, class),
>
> Please avoid doing renames along with functional changes.  It makes reviewing
> extremely hard.
Ok I will move the renames in a different patch.

...
>> @@ -97,7 +97,12 @@ void device_pm_add(struct device *dev)
>>                       dev_name(dev->parent));
>>       list_add_tail(&dev->power.entry, &dpm_list);
>>       mutex_unlock(&dpm_list_mtx);
>> -     plist_head_init(&dev->power.latency_constraints, &dev->power.lock);
>> +     plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
>> +     dev->power.latency_constraints.target_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.default_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.type = PM_QOS_MIN;
>
> Perhaps add a helper doing these assignments?
This code is later moved into the device insertion and removal
functions. Cf. [05/13].

...
>> @@ -464,7 +465,7 @@ struct dev_pm_info {
>>       unsigned long           accounting_timestamp;
>>       void                    *subsys_data;  /* Owned by the subsystem. */
>>  #endif
>> -     struct plist_head       latency_constraints;
>> +     struct pm_qos_constraints       latency_constraints;
>
> Why don't you simply call it "qos"?  The data type provides the information
> about what it's for now.
Ok

...
>> +struct pm_qos_constraints {
>> +     struct plist_head list;
>> +     /*
>> +      * Do not change target_value to 64 bit in order to guarantee
>> +      * accesses atomicity
>> +      */
>
> The comment doesn't belong here.  Please put it outside of the structure
> definition or after the field name (or both, in which case the "inline"
> one may be shorter, like "must not be 64-bit").
Ok

>
>> +     s32 target_value;
>> +     s32 default_value;
>> +     enum pm_qos_type type;
>> +};
>> +
>> +/*
>> + * Struct that is pre-allocated by the caller.
>> + * The handle is kept for future use (update, removal)
>> + */
>>  struct pm_qos_request {
>> -     struct plist_node list;
>> +     struct plist_node node;
>
> Please avoid doing such things along with functional changes.
Ok

...
>> +enum pm_qos_req_action {
>> +     PM_QOS_ADD_REQ,
>> +     PM_QOS_UPDATE_REQ,
>> +     PM_QOS_REMOVE_REQ
>>  };
>
> A comment describing the meaning of these would be helpful.
Ok

...
>> -static inline int pm_qos_get_value(struct pm_qos_object *o)
>> +static inline int pm_qos_get_value(struct pm_qos_constraints *c)
>
> I'd remove the "inline" if you're at it.  It's only a hint if the kernel
> is not built with "always inline" and the compiler should do the inlining
> anyway if that's a better choice.
Ok

...
>> -static inline s32 pm_qos_read_value(struct pm_qos_object *o)
>> +/*
>> + * pm_qos_read_value atomically reads and returns target_value.
>
> We have a standard for writing kerneldoc comments, please follow it.
Ok

>
>> + * target_value is updated upon update of the constraints list, using
>> + * pm_qos_set_value.
>> + *
>> + * Note: The lockless read path depends on the CPU accessing
>> + * target_value atomically.  Atomic access is only guaranteed on all CPU
>> + * types linux supports for 32 bit quantites
>
> You should say "data types" rather than "quantities" here.
Ok

>
>> + */
>> +static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
>>  {
>> -     return o->target_value;
>> +     if (c)
>> +             return c->target_value;
>> +     else
>> +             return 0;
>>  }
>>
>> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
>> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
>>  {
>> -     o->target_value = value;
>> +     c->target_value = value;
>>  }
>
> Well, I'm not sure that this function is necessary at all.  You might as well
> simply remove it as far as I'm concerned.
The idea is to provide an efficient and lockless way to get the
aggregated constraint class value. When the constraints a re changing
the new value is calculated and stored using pm_qos_get_value and
pm_qos_set_value. Then pm_qos_read_value is used to retrieve the
value. For example cpuidle calls pm_qos_request which uses
pm_qos_read_value to get the CPU/DMA minimum latency.

>
>> -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 *req,
>> +                       enum pm_qos_req_action action, int value)
>>  {
>>       unsigned long flags;
>> -     int prev_value, curr_value;
>> +     int prev_value, curr_value, new_value;
>> +     struct pm_qos_object *o = pm_qos_array[req->class];
>> +     struct pm_qos_constraints *c;
>> +
>> +     switch (req->class) {
>> +     case PM_QOS_DEV_LATENCY:
>> +             if (!req->dev) {
>> +                     WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
>> +                     return;
>> +             }
>> +             c = &req->dev->power.latency_constraints;
>> +             break;
>> +     case PM_QOS_CPU_DMA_LATENCY:
>> +     case PM_QOS_NETWORK_LATENCY:
>> +     case PM_QOS_NETWORK_THROUGHPUT:
>> +             c = o->constraints;
>> +             break;
>> +     case PM_QOS_RESERVED:
>> +     default:
>> +             WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
>> +                     "req 0x%p\n", req->class, req);
>> +             return;
>> +     }
>
> Do we _really_ need that switch()?
>
> What about introducing dev_pm_qos_add_request() and friends specifically
> for devices, such that they will take the target device object (dev) as
> their first argument?  Then, you could keep pm_qos_add_request() pretty
> much as is, right?
Yes but in that case I need to duplicate the API functions for devices
(add, update, remove). Those functions will call update_target.
I prefer the way this patch does it: simplify the API functions and
have only 1 place with the constraints management and notification
logic (in update_target).

>
>>
>>       spin_lock_irqsave(&pm_qos_lock, flags);
>> -     prev_value = pm_qos_get_value(o);
>> -     /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
>> -     if (value != PM_QOS_DEFAULT_VALUE) {
>> +
>> +     prev_value = pm_qos_get_value(c);
>> +     if (value == PM_QOS_DEFAULT_VALUE)
>> +             new_value = c->default_value;
>> +     else
>> +             new_value = value;
>
> What about writing that as
>
>        new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;
This is shorter but more difficult to read ;8

>
>> +
>> +     switch (action) {
>> +     case PM_QOS_REMOVE_REQ:
>> +             plist_del(&req->node, &c->list);
>> +             break;
>> +     case PM_QOS_UPDATE_REQ:
>>               /*
>>                * to change the list, we atomically remove, reinit
>>                * with new value and add, then see if the extremal
>>                * changed
>>                */
>> -             plist_del(node, &o->requests);
>> -             plist_node_init(node, value);
>> -             plist_add(node, &o->requests);
>> -     } else if (del) {
>> -             plist_del(node, &o->requests);
>> -     } else {
>> -             plist_add(node, &o->requests);
>> +             plist_del(&req->node, &c->list);
>> +     case PM_QOS_ADD_REQ:
>> +             plist_node_init(&req->node, new_value);
>> +             plist_add(&req->node, &c->list);
>> +             break;
>> +     default:
>> +             /* no action */
>> +             ;
>>       }
>> -     curr_value = pm_qos_get_value(o);
>> -     pm_qos_set_value(o, curr_value);
>> +
>> +     curr_value = pm_qos_get_value(c);
>> +     pm_qos_set_value(c, curr_value);
>>       spin_unlock_irqrestore(&pm_qos_lock, flags);
>>
>>       if (prev_value != curr_value)
>>               blocking_notifier_call_chain(o->notifiers,
>
> That's why I'm thinking that it would be helpful to have a pointer
> to the notifier list from struct pm_qos_constraints .
I think having a per-device notifier list is complicating things. If a
subsystem needs te be notified it needs to register a notifier
callback for _every_ device in the system.
As a first implementation for OMAP the low-level PM code is using a
single notifier to retrieve all the devices latency constraints and
apply them to the pwer domains. I do not see how this could work with
a per-device notifier list.

>
> Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
> "o->notifiers".
Ok

...
>> +static int find_pm_qos_object_by_minor(int minor)
>> +{
>> +     int pm_qos_class;
>> +
>> +     for (pm_qos_class = 0;
>> +             pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
>> +             if (minor ==
>> +                     pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
>> +                     return pm_qos_class;
>> +     }
>> +     return -1;
>> +}
>
> This function doesn't seem to be used anywhere, what's the purpose of it?
It is used by pm_qos_power_open in order to retrieve the class
associated with the MISC device.
BTW this patch is moving the code so that all the MISC related
functions are grouped together.

>
>> +
>>  static int pm_qos_power_open(struct inode *inode, struct file *filp)
>>  {
>>       struct pm_qos_parameters pm_qos_params;
...
>
> Thanks,
> Rafael

Thanks,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-30 22:38   ` Rafael J. Wysocki
  2011-08-02 10:07     ` Jean Pihet
@ 2011-08-02 10:07     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02 10:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Rafael,

2011/7/31 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
...

>> @@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
>>  {
>>       pr_debug("PM: Removing info for %s:%s\n",
>>                dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
>> +     /* Call PM QoS to de-init the per-device latency constraints */
>> +     pm_qos_dev_constraints_deinit(dev);
>
> I'd call this function "dev_pm_qos_constraints_destroy()" (and the previous
> one "dev_pm_qos_constraints_init()" for consistency).
Ok

...
>> +/* Called from the device PM subsystem at device init */
>> +void pm_qos_dev_constraints_init(struct device *dev)
>> +{
>> +     plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
>> +     dev->power.latency_constraints.target_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.default_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.type = PM_QOS_MIN;
>> +     dev->power.latency_constraints_init = 1;
>
> You could avoid adding this field if there were a PM_QOS_UNINITIALIZED
> (or PM_QOS_UNKNOWN) type.
>
> And if you _really_ want to have a separate field, why don't you put it
> into latency_constraints ?
Ok I remove latency_constraints_init and use the type field instead.

...
>
> Thanks,
> Rafael

Thanks,
Jean

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

* Re: [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices
  2011-07-30 22:38   ` Rafael J. Wysocki
@ 2011-08-02 10:07     ` Jean Pihet
  2011-08-02 10:07     ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-02 10:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

Rafael,

2011/7/31 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, July 28, 2011, jean.pihet@newoldbits.com wrote:
...

>> @@ -113,6 +109,8 @@ void device_pm_remove(struct device *dev)
>>  {
>>       pr_debug("PM: Removing info for %s:%s\n",
>>                dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
>> +     /* Call PM QoS to de-init the per-device latency constraints */
>> +     pm_qos_dev_constraints_deinit(dev);
>
> I'd call this function "dev_pm_qos_constraints_destroy()" (and the previous
> one "dev_pm_qos_constraints_init()" for consistency).
Ok

...
>> +/* Called from the device PM subsystem at device init */
>> +void pm_qos_dev_constraints_init(struct device *dev)
>> +{
>> +     plist_head_init(&dev->power.latency_constraints.list, &dev->power.lock);
>> +     dev->power.latency_constraints.target_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.default_value =
>> +                                     PM_QOS_DEV_LAT_DEFAULT_VALUE;
>> +     dev->power.latency_constraints.type = PM_QOS_MIN;
>> +     dev->power.latency_constraints_init = 1;
>
> You could avoid adding this field if there were a PM_QOS_UNINITIALIZED
> (or PM_QOS_UNKNOWN) type.
>
> And if you _really_ want to have a separate field, why don't you put it
> into latency_constraints ?
Ok I remove latency_constraints_init and use the type field instead.

...
>
> Thanks,
> Rafael

Thanks,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
  2011-07-29 22:55   ` Rafael J. Wysocki
  2011-07-29 22:55   ` Rafael J. Wysocki
@ 2011-08-02 18:01   ` Kevin Hilman
  2011-08-02 18:01   ` Kevin Hilman
  3 siblings, 0 replies; 78+ messages in thread
From: Kevin Hilman @ 2011-08-02 18:01 UTC (permalink / raw)
  To: jean.pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

jean.pihet@newoldbits.com writes:

> From: Jean Pihet <j-pihet@ti.com>
>
> Extend the PM QoS kernel API:
> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
> constraints
> - make the pm_qos_add_request API more generic by using a parameter of
> type struct pm_qos_parameters
> - minor clean-ups and rename of struct fields:
>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>   . consistenly use req and params as the API parameters
>   . rename struct pm_qos_request_list to struct pm_qos_request
> - update the in-kernel API callers to the new API
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  arch/arm/plat-omap/i2c.c               |   20 -----
>  drivers/i2c/busses/i2c-omap.c          |   35 ++++++---

More on breaking this patch up...

Since the OMAP I2C driver is not a current PM QoS API user, it doesn't
really belong in this patch which is converting existing PM QoS API
users.  The OMAP I2C conversion should be its own patch.

Kevin

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-07-28  8:30 ` jean.pihet
                     ` (2 preceding siblings ...)
  2011-08-02 18:01   ` Kevin Hilman
@ 2011-08-02 18:01   ` Kevin Hilman
  3 siblings, 0 replies; 78+ messages in thread
From: Kevin Hilman @ 2011-08-02 18:01 UTC (permalink / raw)
  To: jean.pihet
  Cc: Rafael J. Wysocki, Paul Walmsley, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet

jean.pihet@newoldbits.com writes:

> From: Jean Pihet <j-pihet@ti.com>
>
> Extend the PM QoS kernel API:
> - add a new PM QoS class PM_QOS_DEV_LATENCY for device wake-up latency
> constraints
> - make the pm_qos_add_request API more generic by using a parameter of
> type struct pm_qos_parameters
> - minor clean-ups and rename of struct fields:
>   . rename pm_qos_class to class and pm_qos_req to req in internal code
>   . consistenly use req and params as the API parameters
>   . rename struct pm_qos_request_list to struct pm_qos_request
> - update the in-kernel API callers to the new API
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
>  arch/arm/plat-omap/i2c.c               |   20 -----
>  drivers/i2c/busses/i2c-omap.c          |   35 ++++++---

More on breaking this patch up...

Since the OMAP I2C driver is not a current PM QoS API user, it doesn't
really belong in this patch which is converting existing PM QoS API
users.  The OMAP I2C conversion should be its own patch.

Kevin

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-08-02  9:41     ` Jean Pihet
@ 2011-08-02 21:02       ` Rafael J. Wysocki
  2011-08-02 21:02       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02 21:02 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Hi,

On Tuesday, August 02, 2011, Jean Pihet wrote:
...
> I will keep pm_qos_class if the rename brings in some confusion. The
> intention was to simplify the names of the fields in structs with
> explicit names.

Please keep it for now.  You can rename it later if there's a clear
benefit, but I'm not sure still.

> >
> >> +     struct device *dev;
> >>  };
> >>
> >> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
> >> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> >> -             s32 new_value);
> >> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> >> +struct pm_qos_parameters {
> >> +     int class;
> >> +     struct device *dev;
> >> +     s32 value;
> >> +};
> >
> > What exactly is the "dev" member needed for?
> This is the target device that is passed as parameter to the API. It
> is used for constraints of the devices latency class.

Well, I don't like this change.

In fact, I'd prefer it if the old interface were kept unmodified.

> ...
> >> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
> >> +static struct pm_qos_object dev_pm_qos = {
> >> +     .requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> >> +     .notifiers = &dev_lat_notifier,
> >> +     .name = "dev_latency",
> >> +     .target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> >> +     .default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> >> +     .type = PM_QOS_MIN,
> >> +};
> >> +
> >
> > You seem to be confusing things here.  Since devices will have their own lists
> > of requests now (as per the previous patch), the .requests member above is not
> > necessary.  Moreover, it seems to be used incorrectly below.
> The idea was to split the patches as requested previously: first the
> API changes (this very patch [03/13]) and then the actual
> implementation ([04/13]). Is this correct?

The idea is right in general, but so to speak it didn't work out too well.

The most important change is the introduction of struct pm_qos_constraints,
which doesn't need any preparation IMO.  I'd do this possibly early in the
series and I'd do it like this:

+struct pm_qos_constraints {
+       struct plist_head list;
+       s32 target_value;
+       s32 default_value;
+       struct blocking_notifier_head *notifiers;
+};

(more on the notifiers later).  Please note the lack of the type field.

At the same time I'd redefine struct pm_qos_object in the following way:

 struct pm_qos_object {
-       struct plist_head requests;
+       struct pm_qos_constraints *constraints;
-       struct blocking_notifier_head *notifiers;
        struct miscdevice pm_qos_power_miscdev;
        char *name;
-       s32 target_value;       /* Do not change to 64 bit */
-       s32 default_value;
        enum pm_qos_type type;
 };

so for the _existing_ PM QoS classes you can simply use
constraints->list instead of requests, constraints->target_value
instead of target_value, constraints->defaul_value instead of default_value
and constraints->notifiers instead of notifiers.

I wouldn't introduce a "global" PM QoS class for devices.

That should be a relatively simple patch that doesn't change the
existing interface and functionality.

The next patch would be to modify update_target() so that it takes
a pointer to struct pm_qos_constraints instead of the pointers to
struct pm_qos_object and struct plist_node (possibly also to take
an "operation" argument instead of the "del" one).  All it needs is
in struct pm_qos_constraints, so that should be simple too.
The modified update_target() should return a value indicating
whether or not prev_value was different from curr_value, so that
the device PM QoS functions (introduced by the next patch) can use it
to trigger system-wide notifications.

The next patch would introduce the per-device PM QoS by (1) adding
a struct pm_qos_constraints _pointer_ to struct dev_pm_info (assuming
that at least _some_ devices won't use PM QoS) and (2) adding
dev_pm_qos_add/update/remove_request() in drivers/base/power/qos.c,
all of them using the modified update_target().

Now if system-wide notifier chain for devices is necessary, you can
simply define it as a static variable in drivers/base/power/qos.c
without actually adding any "PM QoS object" for this purpose.  Now,
you can use the value returned by the modified update_target() to
decide whether or not to run notifiers from dev_pm_qos_*_request().

Does it make sense to you?

Rafael

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

* Re: [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints
  2011-08-02  9:41     ` Jean Pihet
  2011-08-02 21:02       ` Rafael J. Wysocki
@ 2011-08-02 21:02       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02 21:02 UTC (permalink / raw)
  To: Jean Pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

Hi,

On Tuesday, August 02, 2011, Jean Pihet wrote:
...
> I will keep pm_qos_class if the rename brings in some confusion. The
> intention was to simplify the names of the fields in structs with
> explicit names.

Please keep it for now.  You can rename it later if there's a clear
benefit, but I'm not sure still.

> >
> >> +     struct device *dev;
> >>  };
> >>
> >> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
> >> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> >> -             s32 new_value);
> >> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> >> +struct pm_qos_parameters {
> >> +     int class;
> >> +     struct device *dev;
> >> +     s32 value;
> >> +};
> >
> > What exactly is the "dev" member needed for?
> This is the target device that is passed as parameter to the API. It
> is used for constraints of the devices latency class.

Well, I don't like this change.

In fact, I'd prefer it if the old interface were kept unmodified.

> ...
> >> +static BLOCKING_NOTIFIER_HEAD(dev_lat_notifier);
> >> +static struct pm_qos_object dev_pm_qos = {
> >> +     .requests = PLIST_HEAD_INIT(dev_pm_qos.requests, pm_qos_lock),
> >> +     .notifiers = &dev_lat_notifier,
> >> +     .name = "dev_latency",
> >> +     .target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> >> +     .default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE,
> >> +     .type = PM_QOS_MIN,
> >> +};
> >> +
> >
> > You seem to be confusing things here.  Since devices will have their own lists
> > of requests now (as per the previous patch), the .requests member above is not
> > necessary.  Moreover, it seems to be used incorrectly below.
> The idea was to split the patches as requested previously: first the
> API changes (this very patch [03/13]) and then the actual
> implementation ([04/13]). Is this correct?

The idea is right in general, but so to speak it didn't work out too well.

The most important change is the introduction of struct pm_qos_constraints,
which doesn't need any preparation IMO.  I'd do this possibly early in the
series and I'd do it like this:

+struct pm_qos_constraints {
+       struct plist_head list;
+       s32 target_value;
+       s32 default_value;
+       struct blocking_notifier_head *notifiers;
+};

(more on the notifiers later).  Please note the lack of the type field.

At the same time I'd redefine struct pm_qos_object in the following way:

 struct pm_qos_object {
-       struct plist_head requests;
+       struct pm_qos_constraints *constraints;
-       struct blocking_notifier_head *notifiers;
        struct miscdevice pm_qos_power_miscdev;
        char *name;
-       s32 target_value;       /* Do not change to 64 bit */
-       s32 default_value;
        enum pm_qos_type type;
 };

so for the _existing_ PM QoS classes you can simply use
constraints->list instead of requests, constraints->target_value
instead of target_value, constraints->defaul_value instead of default_value
and constraints->notifiers instead of notifiers.

I wouldn't introduce a "global" PM QoS class for devices.

That should be a relatively simple patch that doesn't change the
existing interface and functionality.

The next patch would be to modify update_target() so that it takes
a pointer to struct pm_qos_constraints instead of the pointers to
struct pm_qos_object and struct plist_node (possibly also to take
an "operation" argument instead of the "del" one).  All it needs is
in struct pm_qos_constraints, so that should be simple too.
The modified update_target() should return a value indicating
whether or not prev_value was different from curr_value, so that
the device PM QoS functions (introduced by the next patch) can use it
to trigger system-wide notifications.

The next patch would introduce the per-device PM QoS by (1) adding
a struct pm_qos_constraints _pointer_ to struct dev_pm_info (assuming
that at least _some_ devices won't use PM QoS) and (2) adding
dev_pm_qos_add/update/remove_request() in drivers/base/power/qos.c,
all of them using the modified update_target().

Now if system-wide notifier chain for devices is necessary, you can
simply define it as a static variable in drivers/base/power/qos.c
without actually adding any "PM QoS object" for this purpose.  Now,
you can use the value returned by the modified update_target() to
decide whether or not to run notifiers from dev_pm_qos_*_request().

Does it make sense to you?

Rafael

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-08-02 10:05     ` Jean Pihet
  2011-08-02 21:13       ` Rafael J. Wysocki
@ 2011-08-02 21:13       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02 21:13 UTC (permalink / raw)
  To: Jean Pihet
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Hi,

On Tuesday, August 02, 2011, Jean Pihet wrote:

...
> >> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> >> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
> >>  {
> >> -     o->target_value = value;
> >> +     c->target_value = value;
> >>  }
> >
> > Well, I'm not sure that this function is necessary at all.  You might as well
> > simply remove it as far as I'm concerned.
> The idea is to provide an efficient and lockless way to get the
> aggregated constraint class value. When the constraints a re changing
> the new value is calculated and stored using pm_qos_get_value and
> pm_qos_set_value. Then pm_qos_read_value is used to retrieve the
> value. For example cpuidle calls pm_qos_request which uses
> pm_qos_read_value to get the CPU/DMA minimum latency.

Still, pm_qos_set_value() is static in this file and doesn't really serve
any specific purpose except for symmetry with pm_qos_read_value().

Anyway, as I said I'm not sure, so it's OK to leave it as is to me too.

> 
> >
> >> -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 *req,
> >> +                       enum pm_qos_req_action action, int value)
> >>  {
> >>       unsigned long flags;
> >> -     int prev_value, curr_value;
> >> +     int prev_value, curr_value, new_value;
> >> +     struct pm_qos_object *o = pm_qos_array[req->class];
> >> +     struct pm_qos_constraints *c;
> >> +
> >> +     switch (req->class) {
> >> +     case PM_QOS_DEV_LATENCY:
> >> +             if (!req->dev) {
> >> +                     WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
> >> +                     return;
> >> +             }
> >> +             c = &req->dev->power.latency_constraints;
> >> +             break;
> >> +     case PM_QOS_CPU_DMA_LATENCY:
> >> +     case PM_QOS_NETWORK_LATENCY:
> >> +     case PM_QOS_NETWORK_THROUGHPUT:
> >> +             c = o->constraints;
> >> +             break;
> >> +     case PM_QOS_RESERVED:
> >> +     default:
> >> +             WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
> >> +                     "req 0x%p\n", req->class, req);
> >> +             return;
> >> +     }
> >
> > Do we _really_ need that switch()?
> >
> > What about introducing dev_pm_qos_add_request() and friends specifically
> > for devices, such that they will take the target device object (dev) as
> > their first argument?  Then, you could keep pm_qos_add_request() pretty
> > much as is, right?
> Yes but in that case I need to duplicate the API functions for devices
> (add, update, remove). Those functions will call update_target.
> I prefer the way this patch does it: simplify the API functions and
> have only 1 place with the constraints management and notification
> logic (in update_target).

The device functions would still call update_target(), but directly on the
device's struct struct pm_qos_constraints, so they wouldn't really duplicate
the existing pm_qos_*_request().

> 
> >
> >>
> >>       spin_lock_irqsave(&pm_qos_lock, flags);
> >> -     prev_value = pm_qos_get_value(o);
> >> -     /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> >> -     if (value != PM_QOS_DEFAULT_VALUE) {
> >> +
> >> +     prev_value = pm_qos_get_value(c);
> >> +     if (value == PM_QOS_DEFAULT_VALUE)
> >> +             new_value = c->default_value;
> >> +     else
> >> +             new_value = value;
> >
> > What about writing that as
> >
> >        new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;
> This is shorter but more difficult to read ;8

That depends on who you ask. :-)

> >
> >> +
> >> +     switch (action) {
> >> +     case PM_QOS_REMOVE_REQ:
> >> +             plist_del(&req->node, &c->list);
> >> +             break;
> >> +     case PM_QOS_UPDATE_REQ:
> >>               /*
> >>                * to change the list, we atomically remove, reinit
> >>                * with new value and add, then see if the extremal
> >>                * changed
> >>                */
> >> -             plist_del(node, &o->requests);
> >> -             plist_node_init(node, value);
> >> -             plist_add(node, &o->requests);
> >> -     } else if (del) {
> >> -             plist_del(node, &o->requests);
> >> -     } else {
> >> -             plist_add(node, &o->requests);
> >> +             plist_del(&req->node, &c->list);
> >> +     case PM_QOS_ADD_REQ:
> >> +             plist_node_init(&req->node, new_value);
> >> +             plist_add(&req->node, &c->list);
> >> +             break;
> >> +     default:
> >> +             /* no action */
> >> +             ;
> >>       }
> >> -     curr_value = pm_qos_get_value(o);
> >> -     pm_qos_set_value(o, curr_value);
> >> +
> >> +     curr_value = pm_qos_get_value(c);
> >> +     pm_qos_set_value(c, curr_value);
> >>       spin_unlock_irqrestore(&pm_qos_lock, flags);
> >>
> >>       if (prev_value != curr_value)
> >>               blocking_notifier_call_chain(o->notifiers,
> >
> > That's why I'm thinking that it would be helpful to have a pointer
> > to the notifier list from struct pm_qos_constraints .
> I think having a per-device notifier list is complicating things. If a
> subsystem needs te be notified it needs to register a notifier
> callback for _every_ device in the system.

I'm not really sure.  For example, why would a video subsystem want to be
notified of a PM QoS change in a keyboard?

> As a first implementation for OMAP the low-level PM code is using a
> single notifier to retrieve all the devices latency constraints and
> apply them to the pwer domains. I do not see how this could work with
> a per-device notifier list.

If you need a global notifier chain, it can be implemented as a separate
static variable as I said in my last reply in the [03/13] thread.

> 
> >
> > Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
> > "o->notifiers".
> Ok
> 
> ...
> >> +static int find_pm_qos_object_by_minor(int minor)
> >> +{
> >> +     int pm_qos_class;
> >> +
> >> +     for (pm_qos_class = 0;
> >> +             pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> >> +             if (minor ==
> >> +                     pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> >> +                     return pm_qos_class;
> >> +     }
> >> +     return -1;
> >> +}
> >
> > This function doesn't seem to be used anywhere, what's the purpose of it?
> It is used by pm_qos_power_open in order to retrieve the class
> associated with the MISC device.
> BTW this patch is moving the code so that all the MISC related
> functions are grouped together.

OK, one more thing that needs to be done in a separate patch. :-)

Thanks,
Rafael

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

* Re: [PATCH 04/13] PM: QoS: implement the per-device latency constraints
  2011-08-02 10:05     ` Jean Pihet
@ 2011-08-02 21:13       ` Rafael J. Wysocki
  2011-08-02 21:13       ` Rafael J. Wysocki
  1 sibling, 0 replies; 78+ messages in thread
From: Rafael J. Wysocki @ 2011-08-02 21:13 UTC (permalink / raw)
  To: Jean Pihet
  Cc: Paul Walmsley, Kevin Hilman, Magnus Damm, Linux PM mailing list,
	linux-omap, markgross, broonie, Jean Pihet

Hi,

On Tuesday, August 02, 2011, Jean Pihet wrote:

...
> >> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> >> +static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
> >>  {
> >> -     o->target_value = value;
> >> +     c->target_value = value;
> >>  }
> >
> > Well, I'm not sure that this function is necessary at all.  You might as well
> > simply remove it as far as I'm concerned.
> The idea is to provide an efficient and lockless way to get the
> aggregated constraint class value. When the constraints a re changing
> the new value is calculated and stored using pm_qos_get_value and
> pm_qos_set_value. Then pm_qos_read_value is used to retrieve the
> value. For example cpuidle calls pm_qos_request which uses
> pm_qos_read_value to get the CPU/DMA minimum latency.

Still, pm_qos_set_value() is static in this file and doesn't really serve
any specific purpose except for symmetry with pm_qos_read_value().

Anyway, as I said I'm not sure, so it's OK to leave it as is to me too.

> 
> >
> >> -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 *req,
> >> +                       enum pm_qos_req_action action, int value)
> >>  {
> >>       unsigned long flags;
> >> -     int prev_value, curr_value;
> >> +     int prev_value, curr_value, new_value;
> >> +     struct pm_qos_object *o = pm_qos_array[req->class];
> >> +     struct pm_qos_constraints *c;
> >> +
> >> +     switch (req->class) {
> >> +     case PM_QOS_DEV_LATENCY:
> >> +             if (!req->dev) {
> >> +                     WARN(1, KERN_ERR "PM QoS API called with NULL dev\n");
> >> +                     return;
> >> +             }
> >> +             c = &req->dev->power.latency_constraints;
> >> +             break;
> >> +     case PM_QOS_CPU_DMA_LATENCY:
> >> +     case PM_QOS_NETWORK_LATENCY:
> >> +     case PM_QOS_NETWORK_THROUGHPUT:
> >> +             c = o->constraints;
> >> +             break;
> >> +     case PM_QOS_RESERVED:
> >> +     default:
> >> +             WARN(1, KERN_ERR "PM QoS API called with wrong class %d, "
> >> +                     "req 0x%p\n", req->class, req);
> >> +             return;
> >> +     }
> >
> > Do we _really_ need that switch()?
> >
> > What about introducing dev_pm_qos_add_request() and friends specifically
> > for devices, such that they will take the target device object (dev) as
> > their first argument?  Then, you could keep pm_qos_add_request() pretty
> > much as is, right?
> Yes but in that case I need to duplicate the API functions for devices
> (add, update, remove). Those functions will call update_target.
> I prefer the way this patch does it: simplify the API functions and
> have only 1 place with the constraints management and notification
> logic (in update_target).

The device functions would still call update_target(), but directly on the
device's struct struct pm_qos_constraints, so they wouldn't really duplicate
the existing pm_qos_*_request().

> 
> >
> >>
> >>       spin_lock_irqsave(&pm_qos_lock, flags);
> >> -     prev_value = pm_qos_get_value(o);
> >> -     /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> >> -     if (value != PM_QOS_DEFAULT_VALUE) {
> >> +
> >> +     prev_value = pm_qos_get_value(c);
> >> +     if (value == PM_QOS_DEFAULT_VALUE)
> >> +             new_value = c->default_value;
> >> +     else
> >> +             new_value = value;
> >
> > What about writing that as
> >
> >        new_value = value != PM_QOS_DEFAULT_VALUE ? value : c->default_value;
> This is shorter but more difficult to read ;8

That depends on who you ask. :-)

> >
> >> +
> >> +     switch (action) {
> >> +     case PM_QOS_REMOVE_REQ:
> >> +             plist_del(&req->node, &c->list);
> >> +             break;
> >> +     case PM_QOS_UPDATE_REQ:
> >>               /*
> >>                * to change the list, we atomically remove, reinit
> >>                * with new value and add, then see if the extremal
> >>                * changed
> >>                */
> >> -             plist_del(node, &o->requests);
> >> -             plist_node_init(node, value);
> >> -             plist_add(node, &o->requests);
> >> -     } else if (del) {
> >> -             plist_del(node, &o->requests);
> >> -     } else {
> >> -             plist_add(node, &o->requests);
> >> +             plist_del(&req->node, &c->list);
> >> +     case PM_QOS_ADD_REQ:
> >> +             plist_node_init(&req->node, new_value);
> >> +             plist_add(&req->node, &c->list);
> >> +             break;
> >> +     default:
> >> +             /* no action */
> >> +             ;
> >>       }
> >> -     curr_value = pm_qos_get_value(o);
> >> -     pm_qos_set_value(o, curr_value);
> >> +
> >> +     curr_value = pm_qos_get_value(c);
> >> +     pm_qos_set_value(c, curr_value);
> >>       spin_unlock_irqrestore(&pm_qos_lock, flags);
> >>
> >>       if (prev_value != curr_value)
> >>               blocking_notifier_call_chain(o->notifiers,
> >
> > That's why I'm thinking that it would be helpful to have a pointer
> > to the notifier list from struct pm_qos_constraints .
> I think having a per-device notifier list is complicating things. If a
> subsystem needs te be notified it needs to register a notifier
> callback for _every_ device in the system.

I'm not really sure.  For example, why would a video subsystem want to be
notified of a PM QoS change in a keyboard?

> As a first implementation for OMAP the low-level PM code is using a
> single notifier to retrieve all the devices latency constraints and
> apply them to the pwer domains. I do not see how this could work with
> a per-device notifier list.

If you need a global notifier chain, it can be implemented as a separate
static variable as I said in my last reply in the [03/13] thread.

> 
> >
> > Besides, you can use "pm_qos_array[req->class]->notifiers" instead of
> > "o->notifiers".
> Ok
> 
> ...
> >> +static int find_pm_qos_object_by_minor(int minor)
> >> +{
> >> +     int pm_qos_class;
> >> +
> >> +     for (pm_qos_class = 0;
> >> +             pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> >> +             if (minor ==
> >> +                     pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> >> +                     return pm_qos_class;
> >> +     }
> >> +     return -1;
> >> +}
> >
> > This function doesn't seem to be used anywhere, what's the purpose of it?
> It is used by pm_qos_power_open in order to retrieve the class
> associated with the MISC device.
> BTW this patch is moving the code so that all the MISC related
> functions are grouped together.

OK, one more thing that needs to be done in a separate patch. :-)

Thanks,
Rafael

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29 18:00       ` Todd Poynor
  2011-08-11 15:09         ` Jean Pihet
@ 2011-08-11 15:09         ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-11 15:09 UTC (permalink / raw)
  To: Todd Poynor
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Hi Todd,

On Fri, Jul 29, 2011 at 8:00 PM, Todd Poynor <toddpoynor@google.com> wrote:
> On Fri, Jul 29, 2011 at 10:47:43AM +0200, Jean Pihet wrote:
>> On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
> ...
>> > All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
>> > free_new_user = 1.
>> free_new_user = 1 is only needed if no existing constraint has been
>> found, i.e. user stays at NULL. This is implemented in the check for
>> an existing constraint (plist_for_each_entry(...)).
>
> Oops, I meant to say it applies in all cases where min_latency ==
> PM_QOS_DEV_LAT_DEFAULT_VALUE, since the new node is only used for
> adding a constraint (and no existing constraint found).  I'd suggest
> something like:
>
>        if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
>                new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
>                        GFP_KERNEL);
>                <check NULL return>
>                free_new_user = 1;
>        }
>
> and then set free_new_user = 0 only if no existing constraint is found
> for the add case.  Because it's easy to miss cases where the
> allocated memory needs to be freed when that's not the default, and you
> might as well skip the allocate on a constraint removal.  Pretty minor
> point, though.

This has been addressed in the latest patch set (v4).

Regards,
Jean

>
>
> Todd
>

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

* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
  2011-07-29 18:00       ` Todd Poynor
@ 2011-08-11 15:09         ` Jean Pihet
  2011-08-11 15:09         ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-11 15:09 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet

Hi Todd,

On Fri, Jul 29, 2011 at 8:00 PM, Todd Poynor <toddpoynor@google.com> wrote:
> On Fri, Jul 29, 2011 at 10:47:43AM +0200, Jean Pihet wrote:
>> On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
> ...
>> > All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
>> > free_new_user = 1.
>> free_new_user = 1 is only needed if no existing constraint has been
>> found, i.e. user stays at NULL. This is implemented in the check for
>> an existing constraint (plist_for_each_entry(...)).
>
> Oops, I meant to say it applies in all cases where min_latency ==
> PM_QOS_DEV_LAT_DEFAULT_VALUE, since the new node is only used for
> adding a constraint (and no existing constraint found).  I'd suggest
> something like:
>
>        if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
>                new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
>                        GFP_KERNEL);
>                <check NULL return>
>                free_new_user = 1;
>        }
>
> and then set free_new_user = 0 only if no existing constraint is found
> for the add case.  Because it's easy to miss cases where the
> allocated memory needs to be freed when that's not the default, and you
> might as well skip the allocate on a constraint removal.  Pretty minor
> point, though.

This has been addressed in the latest patch set (v4).

Regards,
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] 78+ messages in thread

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-08-02  8:57       ` Jean Pihet
  2011-08-11 15:12         ` Jean Pihet
@ 2011-08-11 15:12         ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-11 15:12 UTC (permalink / raw)
  To: Todd Poynor
  Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet

Todd,

On Tue, Aug 2, 2011 at 10:57 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> Todd,
>
> On Fri, Jul 29, 2011 at 10:50 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
>> On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
>>> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
> ...
>
>>>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>>>> index 9af0847..63c3e7a 100644
>>>> --- a/arch/arm/mach-omap2/powerdomain.c
>>>> +++ b/arch/arm/mach-omap2/powerdomain.c
>>>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>>>       pwrdm->state_counter[pwrdm->state] = 1;
>>>>
>>>> +     /* Early init of the next power state */
>>>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>>>> +
>>>
>>> Wanted to check that it's OK to initialize the next state of a power
>>> domain to RETENTION early in the boot sequence.  I believe patches
>>> have been previously discussed that set the state to ON to ensure the
>>> domain doesn't go to a lower state, and possibly lose context, before
>>> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
>>> a doublecheck.
>> Indeed I need to check the behavior for OMAP3 & 4 which seem to
>> initialize the pwrdm states differently.
>> BTW the patch that inits all pwrdms to ON is not yet in l-o master
>> that is why I (lazily) submitted this one for now.
>
> Ok I will update the patch to make it compliant with [1]. v4 will
> include this change.
>
> Thanks,
> Jean
>
> [1] http://marc.info/?l=linux-arm-kernel&m=131052762623823&w=2

After more thinking I now realize there is a problem with the PM early
init, PM late init and the constraints framework which all setup the
power domains next states in a non-coherent way.
Definitely this needs to be revisited. More to come on this!

There is a comment about that in [00/15] of the v4 patch set.

Regards,
Jean

>
>>
>>>
>>>
>>> Todd
>

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

* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
  2011-08-02  8:57       ` Jean Pihet
@ 2011-08-11 15:12         ` Jean Pihet
  2011-08-11 15:12         ` Jean Pihet
  1 sibling, 0 replies; 78+ messages in thread
From: Jean Pihet @ 2011-08-11 15:12 UTC (permalink / raw)
  To: Todd Poynor
  Cc: Rafael J. Wysocki, Paul Walmsley, Kevin Hilman, Magnus Damm,
	Linux PM mailing list, linux-omap, markgross, broonie,
	Jean Pihet, rnayak

Todd,

On Tue, Aug 2, 2011 at 10:57 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> Todd,
>
> On Fri, Jul 29, 2011 at 10:50 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
>> On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
>>> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
> ...
>
>>>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>>>> index 9af0847..63c3e7a 100644
>>>> --- a/arch/arm/mach-omap2/powerdomain.c
>>>> +++ b/arch/arm/mach-omap2/powerdomain.c
>>>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>>>       pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>>>       pwrdm->state_counter[pwrdm->state] = 1;
>>>>
>>>> +     /* Early init of the next power state */
>>>> +     pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>>>> +
>>>
>>> Wanted to check that it's OK to initialize the next state of a power
>>> domain to RETENTION early in the boot sequence.  I believe patches
>>> have been previously discussed that set the state to ON to ensure the
>>> domain doesn't go to a lower state, and possibly lose context, before
>>> the PM subsystem is setup to handle it?  Not sure, thought maybe worth
>>> a doublecheck.
>> Indeed I need to check the behavior for OMAP3 & 4 which seem to
>> initialize the pwrdm states differently.
>> BTW the patch that inits all pwrdms to ON is not yet in l-o master
>> that is why I (lazily) submitted this one for now.
>
> Ok I will update the patch to make it compliant with [1]. v4 will
> include this change.
>
> Thanks,
> Jean
>
> [1] http://marc.info/?l=linux-arm-kernel&m=131052762623823&w=2

After more thinking I now realize there is a problem with the PM early
init, PM late init and the constraints framework which all setup the
power domains next states in a non-coherent way.
Definitely this needs to be revisited. More to come on this!

There is a comment about that in [00/15] of the v4 patch set.

Regards,
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] 78+ messages in thread

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

Thread overview: 78+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-28  8:30 [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class jean.pihet
2011-07-28  8:30 ` [PATCH 01/13] PM: QoS: rename pm_qos_params files to pm_qos jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-29 21:57   ` Rafael J. Wysocki
2011-08-02  9:31     ` Jean Pihet
2011-08-02  9:47       ` Rafael J. Wysocki
2011-08-02  9:47       ` Rafael J. Wysocki
2011-07-28  8:30 ` [PATCH 02/13] PM: add a per-device wake-up latency constraints plist jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-29 21:58   ` Rafael J. Wysocki
2011-07-29 21:58   ` Rafael J. Wysocki
2011-07-28  8:30 ` [PATCH 03/13] PM: QoS: extend the in-kernel API with per-device latency constraints jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-29 22:55   ` Rafael J. Wysocki
2011-07-29 22:55   ` Rafael J. Wysocki
2011-08-02  9:41     ` Jean Pihet
2011-08-02 21:02       ` Rafael J. Wysocki
2011-08-02 21:02       ` Rafael J. Wysocki
2011-08-02  9:41     ` Jean Pihet
2011-08-02 18:01   ` Kevin Hilman
2011-08-02 18:01   ` Kevin Hilman
2011-07-28  8:30 ` [PATCH 04/13] PM: QoS: implement the " jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-30 22:30   ` Rafael J. Wysocki
2011-08-02 10:05     ` Jean Pihet
2011-08-02 21:13       ` Rafael J. Wysocki
2011-08-02 21:13       ` Rafael J. Wysocki
2011-08-02 10:05     ` Jean Pihet
2011-07-30 22:30   ` Rafael J. Wysocki
2011-07-28  8:30 ` [PATCH 05/13] PM: QoS: support the dynamic insertion and removal of devices jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-30 22:38   ` Rafael J. Wysocki
2011-07-30 22:38   ` Rafael J. Wysocki
2011-08-02 10:07     ` Jean Pihet
2011-08-02 10:07     ` Jean Pihet
2011-07-28  8:30 ` [PATCH 06/13] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 07/13] OMAP PM: early init of the pwrdms states jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-29  8:08   ` Todd Poynor
2011-07-29  8:50     ` Jean Pihet
2011-07-29  8:50     ` Jean Pihet
2011-08-02  8:57       ` Jean Pihet
2011-08-02  8:57       ` Jean Pihet
2011-08-11 15:12         ` Jean Pihet
2011-08-11 15:12         ` Jean Pihet
2011-07-29  8:08   ` Todd Poynor
2011-07-28  8:30 ` [PATCH 08/13] OMAP2+: powerdomain: control power domains next state jean.pihet
2011-07-29  7:59   ` Todd Poynor
2011-07-29  7:59   ` Todd Poynor
2011-07-29  8:47     ` Jean Pihet
2011-07-29  8:47     ` Jean Pihet
2011-07-29 18:00       ` Todd Poynor
2011-07-29 18:00       ` Todd Poynor
2011-08-11 15:09         ` Jean Pihet
2011-08-11 15:09         ` Jean Pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 09/13] OMAP3: powerdomain data: add wake-up latency figures jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 10/13] OMAP4: " jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 11/13] OMAP2+: omap_hwmod: manage the wake-up latency constraints jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 12/13] OMAP: PM CONSTRAINTS: implement the devices " jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28  8:30 ` [PATCH 13/13] OMAP2+: cpuidle only influences the MPU state jean.pihet
2011-07-28  8:30 ` jean.pihet
2011-07-28 13:14 ` [RFC/PATCH v3 00/13] PM QoS: add a per-device latency constraints class mark gross
2011-07-29  8:37   ` Jean Pihet
2011-07-29  8:37   ` Jean Pihet
2011-07-29 14:24     ` mark gross
2011-07-29 14:24     ` mark gross
2011-07-29 21:46       ` Rafael J. Wysocki
2011-07-31 17:38         ` mark gross
2011-07-31 17:38         ` [linux-pm] " mark gross
2011-07-29 21:46       ` Rafael J. Wysocki
2011-07-29 21:25 ` Rafael J. Wysocki
2011-07-29 21:25 ` Rafael J. Wysocki

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.