aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Gross <mgross@linux.intel.com>2010-05-05 19:59:26 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-05-10 17:08:19 -0400
commited77134bfccf5e75b6cbadab268e559dbe6a4ebb (patch)
treedae087a617ab3d9af8673d1905dbca3bcd57e89e
parent0fef8b1e83c4ab08cf1304dbebcfd749caf4f187 (diff)
PM QOS update
This patch changes the string based list management to a handle base implementation to help with the hot path use of pm-qos, it also renames much of the API to use "request" as opposed to "requirement" that was used in the initial implementation. I did this because request more accurately represents what it actually does. Also, I added a string based ABI for users wanting to use a string interface. So if the user writes 0xDDDDDDDD formatted hex it will be accepted by the interface. (someone asked me for it and I don't think it hurts anything.) This patch updates some documentation input I got from Randy. Signed-off-by: markgross <mgross@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--Documentation/power/pm_qos_interface.txt48
-rw-r--r--drivers/acpi/processor_idle.c2
-rw-r--r--drivers/cpuidle/governors/ladder.c2
-rw-r--r--drivers/cpuidle/governors/menu.c2
-rw-r--r--drivers/net/e1000e/netdev.c22
-rw-r--r--drivers/net/igbvf/netdev.c6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c11
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/pm_qos_params.h14
-rw-r--r--include/sound/pcm.h3
-rw-r--r--kernel/pm_qos_params.c214
-rw-r--r--net/mac80211/mlme.c2
-rw-r--r--sound/core/pcm.c3
-rw-r--r--sound/core/pcm_native.c14
14 files changed, 176 insertions, 171 deletions
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index c40866e8b957..bfed898a03fc 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -18,44 +18,46 @@ and pm_qos_params.h. This is done because having the available parameters
18being runtime configurable or changeable from a driver was seen as too easy to 18being runtime configurable or changeable from a driver was seen as too easy to
19abuse. 19abuse.
20 20
21For each parameter a list of performance requirements is maintained along with 21For each parameter a list of performance requests is maintained along with
22an aggregated target value. The aggregated target value is updated with 22an aggregated target value. The aggregated target value is updated with
23changes to the requirement list or elements of the list. Typically the 23changes to the request list or elements of the list. Typically the
24aggregated target value is simply the max or min of the requirement values held 24aggregated target value is simply the max or min of the request values held
25in the parameter list elements. 25in the parameter list elements.
26 26
27From kernel mode the use of this interface is simple: 27From kernel mode the use of this interface is simple:
28pm_qos_add_requirement(param_id, name, target_value):
29Will insert a named element in the list for that identified PM_QOS parameter
30with the target value. Upon change to this list the new target is recomputed
31and any registered notifiers are called only if the target value is now
32different.
33 28
34pm_qos_update_requirement(param_id, name, new_target_value): 29handle = pm_qos_add_request(param_class, target_value):
35Will search the list identified by the param_id for the named list element and 30Will insert an element into the list for that identified PM_QOS class with the
36then update its target value, calling the notification tree if the aggregated 31target value. Upon change to this list the new target is recomputed and any
37target is changed. with that name is already registered. 32registered notifiers are called only if the target value is now different.
33Clients of pm_qos need to save the returned handle.
38 34
39pm_qos_remove_requirement(param_id, name): 35void pm_qos_update_request(handle, new_target_value):
40Will search the identified list for the named element and remove it, after 36Will update the list element pointed to by the handle with the new target value
41removal it will update the aggregate target and call the notification tree if 37and recompute the new aggregated target, calling the notification tree if the
42the target was changed as a result of removing the named requirement. 38target is changed.
39
40void pm_qos_remove_request(handle):
41Will remove the element. After removal it will update the aggregate target and
42call the notification tree if the target was changed as a result of removing
43the request.
43 44
44 45
45From user mode: 46From user mode:
46Only processes can register a pm_qos requirement. To provide for automatic 47Only processes can register a pm_qos request. To provide for automatic
47cleanup for process the interface requires the process to register its 48cleanup of a process, the interface requires the process to register its
48parameter requirements in the following way: 49parameter requests in the following way:
49 50
50To register the default pm_qos target for the specific parameter, the process 51To register the default pm_qos target for the specific parameter, the process
51must open one of /dev/[cpu_dma_latency, network_latency, network_throughput] 52must open one of /dev/[cpu_dma_latency, network_latency, network_throughput]
52 53
53As long as the device node is held open that process has a registered 54As long as the device node is held open that process has a registered
54requirement on the parameter. The name of the requirement is "process_<PID>" 55request on the parameter.
55derived from the current->pid from within the open system call.
56 56
57To change the requested target value the process needs to write a s32 value to 57To change the requested target value the process needs to write an s32 value to
58the open device node. This translates to a pm_qos_update_requirement call. 58the open device node. Alternatively the user mode program could write a hex
59string for the value using 10 char long format e.g. "0x12345678". This
60translates to a pm_qos_update_request call.
59 61
60To remove the user mode request for a target value simply close the device 62To remove the user mode request for a target value simply close the device
61node. 63node.
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 5939e7f7d8e9..c3817e1f32c7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -698,7 +698,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
698 "max_cstate: C%d\n" 698 "max_cstate: C%d\n"
699 "maximum allowed latency: %d usec\n", 699 "maximum allowed latency: %d usec\n",
700 pr->power.state ? pr->power.state - pr->power.states : 0, 700 pr->power.state ? pr->power.state - pr->power.states : 0,
701 max_cstate, pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)); 701 max_cstate, pm_qos_request(PM_QOS_CPU_DMA_LATENCY));
702 702
703 seq_puts(seq, "states:\n"); 703 seq_puts(seq, "states:\n");
704 704
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 1c1ceb4f218f..12c98900dcf8 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -67,7 +67,7 @@ static int ladder_select_state(struct cpuidle_device *dev)
67 struct ladder_device *ldev = &__get_cpu_var(ladder_devices); 67 struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
68 struct ladder_device_state *last_state; 68 struct ladder_device_state *last_state;
69 int last_residency, last_idx = ldev->last_state_idx; 69 int last_residency, last_idx = ldev->last_state_idx;
70 int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); 70 int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
71 71
72 /* Special case when user has set very strict latency requirement */ 72 /* Special case when user has set very strict latency requirement */
73 if (unlikely(latency_req == 0)) { 73 if (unlikely(latency_req == 0)) {
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f8e57c6303f2..b81ad9c731ae 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -182,7 +182,7 @@ static u64 div_round64(u64 dividend, u32 divisor)
182static int menu_select(struct cpuidle_device *dev) 182static int menu_select(struct cpuidle_device *dev)
183{ 183{
184 struct menu_device *data = &__get_cpu_var(menu_devices); 184 struct menu_device *data = &__get_cpu_var(menu_devices);
185 int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); 185 int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
186 int i; 186 int i;
187 int multiplier; 187 int multiplier;
188 188
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index dbf81788bb40..d5d55c6a373f 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2524,12 +2524,12 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
2524 * excessive C-state transition latencies result in 2524 * excessive C-state transition latencies result in
2525 * dropped transactions. 2525 * dropped transactions.
2526 */ 2526 */
2527 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, 2527 pm_qos_update_request(
2528 adapter->netdev->name, 55); 2528 adapter->netdev->pm_qos_req, 55);
2529 } else { 2529 } else {
2530 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, 2530 pm_qos_update_request(
2531 adapter->netdev->name, 2531 adapter->netdev->pm_qos_req,
2532 PM_QOS_DEFAULT_VALUE); 2532 PM_QOS_DEFAULT_VALUE);
2533 } 2533 }
2534 } 2534 }
2535 2535
@@ -2824,8 +2824,8 @@ int e1000e_up(struct e1000_adapter *adapter)
2824 2824
2825 /* DMA latency requirement to workaround early-receive/jumbo issue */ 2825 /* DMA latency requirement to workaround early-receive/jumbo issue */
2826 if (adapter->flags & FLAG_HAS_ERT) 2826 if (adapter->flags & FLAG_HAS_ERT)
2827 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, 2827 adapter->netdev->pm_qos_req =
2828 adapter->netdev->name, 2828 pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
2829 PM_QOS_DEFAULT_VALUE); 2829 PM_QOS_DEFAULT_VALUE);
2830 2830
2831 /* hardware has been reset, we need to reload some things */ 2831 /* hardware has been reset, we need to reload some things */
@@ -2887,9 +2887,11 @@ void e1000e_down(struct e1000_adapter *adapter)
2887 e1000_clean_tx_ring(adapter); 2887 e1000_clean_tx_ring(adapter);
2888 e1000_clean_rx_ring(adapter); 2888 e1000_clean_rx_ring(adapter);
2889 2889
2890 if (adapter->flags & FLAG_HAS_ERT) 2890 if (adapter->flags & FLAG_HAS_ERT) {
2891 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, 2891 pm_qos_remove_request(
2892 adapter->netdev->name); 2892 adapter->netdev->pm_qos_req);
2893 adapter->netdev->pm_qos_req = NULL;
2894 }
2893 2895
2894 /* 2896 /*
2895 * TODO: for power management, we could drop the link and 2897 * TODO: for power management, we could drop the link and
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 1b1edad1eb5e..f16e981812a9 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -48,6 +48,7 @@
48#define DRV_VERSION "1.0.0-k0" 48#define DRV_VERSION "1.0.0-k0"
49char igbvf_driver_name[] = "igbvf"; 49char igbvf_driver_name[] = "igbvf";
50const char igbvf_driver_version[] = DRV_VERSION; 50const char igbvf_driver_version[] = DRV_VERSION;
51struct pm_qos_request_list *igbvf_driver_pm_qos_req;
51static const char igbvf_driver_string[] = 52static const char igbvf_driver_string[] =
52 "Intel(R) Virtual Function Network Driver"; 53 "Intel(R) Virtual Function Network Driver";
53static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation."; 54static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
@@ -2899,7 +2900,7 @@ static int __init igbvf_init_module(void)
2899 printk(KERN_INFO "%s\n", igbvf_copyright); 2900 printk(KERN_INFO "%s\n", igbvf_copyright);
2900 2901
2901 ret = pci_register_driver(&igbvf_driver); 2902 ret = pci_register_driver(&igbvf_driver);
2902 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name, 2903 igbvf_driver_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
2903 PM_QOS_DEFAULT_VALUE); 2904 PM_QOS_DEFAULT_VALUE);
2904 2905
2905 return ret; 2906 return ret;
@@ -2915,7 +2916,8 @@ module_init(igbvf_init_module);
2915static void __exit igbvf_exit_module(void) 2916static void __exit igbvf_exit_module(void)
2916{ 2917{
2917 pci_unregister_driver(&igbvf_driver); 2918 pci_unregister_driver(&igbvf_driver);
2918 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name); 2919 pm_qos_remove_request(igbvf_driver_pm_qos_req);
2920 igbvf_driver_pm_qos_req = NULL;
2919} 2921}
2920module_exit(igbvf_exit_module); 2922module_exit(igbvf_exit_module);
2921 2923
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 9b72c45a7748..2b05fe5e994c 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -174,6 +174,8 @@ that only one external action is invoked at a time.
174#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" 174#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
175#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" 175#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
176 176
177struct pm_qos_request_list *ipw2100_pm_qos_req;
178
177/* Debugging stuff */ 179/* Debugging stuff */
178#ifdef CONFIG_IPW2100_DEBUG 180#ifdef CONFIG_IPW2100_DEBUG
179#define IPW2100_RX_DEBUG /* Reception debugging */ 181#define IPW2100_RX_DEBUG /* Reception debugging */
@@ -1739,7 +1741,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
1739 /* the ipw2100 hardware really doesn't want power management delays 1741 /* the ipw2100 hardware really doesn't want power management delays
1740 * longer than 175usec 1742 * longer than 175usec
1741 */ 1743 */
1742 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175); 1744 pm_qos_update_request(ipw2100_pm_qos_req, 175);
1743 1745
1744 /* If the interrupt is enabled, turn it off... */ 1746 /* If the interrupt is enabled, turn it off... */
1745 spin_lock_irqsave(&priv->low_lock, flags); 1747 spin_lock_irqsave(&priv->low_lock, flags);
@@ -1887,8 +1889,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
1887 ipw2100_disable_interrupts(priv); 1889 ipw2100_disable_interrupts(priv);
1888 spin_unlock_irqrestore(&priv->low_lock, flags); 1890 spin_unlock_irqrestore(&priv->low_lock, flags);
1889 1891
1890 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 1892 pm_qos_update_request(ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
1891 PM_QOS_DEFAULT_VALUE);
1892 1893
1893 /* We have to signal any supplicant if we are disassociating */ 1894 /* We have to signal any supplicant if we are disassociating */
1894 if (associated) 1895 if (associated)
@@ -6669,7 +6670,7 @@ static int __init ipw2100_init(void)
6669 if (ret) 6670 if (ret)
6670 goto out; 6671 goto out;
6671 6672
6672 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 6673 ipw2100_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
6673 PM_QOS_DEFAULT_VALUE); 6674 PM_QOS_DEFAULT_VALUE);
6674#ifdef CONFIG_IPW2100_DEBUG 6675#ifdef CONFIG_IPW2100_DEBUG
6675 ipw2100_debug_level = debug; 6676 ipw2100_debug_level = debug;
@@ -6692,7 +6693,7 @@ static void __exit ipw2100_exit(void)
6692 &driver_attr_debug_level); 6693 &driver_attr_debug_level);
6693#endif 6694#endif
6694 pci_unregister_driver(&ipw2100_pci_driver); 6695 pci_unregister_driver(&ipw2100_pci_driver);
6695 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100"); 6696 pm_qos_remove_request(ipw2100_pm_qos_req);
6696} 6697}
6697 6698
6698module_init(ipw2100_init); 6699module_init(ipw2100_init);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index fa8b47637997..3857517f1ca5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -31,6 +31,7 @@
31#include <linux/if_link.h> 31#include <linux/if_link.h>
32 32
33#ifdef __KERNEL__ 33#ifdef __KERNEL__
34#include <linux/pm_qos_params.h>
34#include <linux/timer.h> 35#include <linux/timer.h>
35#include <linux/delay.h> 36#include <linux/delay.h>
36#include <linux/mm.h> 37#include <linux/mm.h>
@@ -711,6 +712,9 @@ struct net_device {
711 * the interface. 712 * the interface.
712 */ 713 */
713 char name[IFNAMSIZ]; 714 char name[IFNAMSIZ];
715
716 struct pm_qos_request_list *pm_qos_req;
717
714 /* device name hash chain */ 718 /* device name hash chain */
715 struct hlist_node name_hlist; 719 struct hlist_node name_hlist;
716 /* snmp alias */ 720 /* snmp alias */
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index d74f75ed1e47..8ba440e5eb7f 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -14,12 +14,14 @@
14#define PM_QOS_NUM_CLASSES 4 14#define PM_QOS_NUM_CLASSES 4
15#define PM_QOS_DEFAULT_VALUE -1 15#define PM_QOS_DEFAULT_VALUE -1
16 16
17int pm_qos_add_requirement(int qos, char *name, s32 value); 17struct pm_qos_request_list;
18int pm_qos_update_requirement(int qos, char *name, s32 new_value);
19void pm_qos_remove_requirement(int qos, char *name);
20 18
21int pm_qos_requirement(int qos); 19struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value);
20void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
21 s32 new_value);
22void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
22 23
23int pm_qos_add_notifier(int qos, struct notifier_block *notifier); 24int pm_qos_request(int pm_qos_class);
24int pm_qos_remove_notifier(int qos, struct notifier_block *notifier); 25int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
26int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
25 27
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 8b611a561985..dd76cdede64d 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -29,6 +29,7 @@
29#include <linux/poll.h> 29#include <linux/poll.h>
30#include <linux/mm.h> 30#include <linux/mm.h>
31#include <linux/bitops.h> 31#include <linux/bitops.h>
32#include <linux/pm_qos_params.h>
32 33
33#define snd_pcm_substream_chip(substream) ((substream)->private_data) 34#define snd_pcm_substream_chip(substream) ((substream)->private_data)
34#define snd_pcm_chip(pcm) ((pcm)->private_data) 35#define snd_pcm_chip(pcm) ((pcm)->private_data)
@@ -365,7 +366,7 @@ struct snd_pcm_substream {
365 int number; 366 int number;
366 char name[32]; /* substream name */ 367 char name[32]; /* substream name */
367 int stream; /* stream (direction) */ 368 int stream; /* stream (direction) */
368 char latency_id[20]; /* latency identifier */ 369 struct pm_qos_request_list *latency_pm_qos_req; /* pm_qos request */
369 size_t buffer_bytes_max; /* limit ring buffer size */ 370 size_t buffer_bytes_max; /* limit ring buffer size */
370 struct snd_dma_buffer dma_buffer; 371 struct snd_dma_buffer dma_buffer;
371 unsigned int dma_buf_id; 372 unsigned int dma_buf_id;
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index 3db49b9ca374..a1aea040eb57 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -2,7 +2,7 @@
2 * This module exposes the interface to kernel space for specifying 2 * This module exposes the interface to kernel space for specifying
3 * QoS dependencies. It provides infrastructure for registration of: 3 * QoS dependencies. It provides infrastructure for registration of:
4 * 4 *
5 * Dependents on a QoS value : register requirements 5 * Dependents on a QoS value : register requests
6 * Watchers of QoS value : get notified when target QoS value changes 6 * Watchers of QoS value : get notified when target QoS value changes
7 * 7 *
8 * This QoS design is best effort based. Dependents register their QoS needs. 8 * This QoS design is best effort based. Dependents register their QoS needs.
@@ -14,19 +14,21 @@
14 * timeout: usec <-- currently not used. 14 * timeout: usec <-- currently not used.
15 * throughput: kbs (kilo byte / sec) 15 * throughput: kbs (kilo byte / sec)
16 * 16 *
17 * There are lists of pm_qos_objects each one wrapping requirements, notifiers 17 * There are lists of pm_qos_objects each one wrapping requests, notifiers
18 * 18 *
19 * User mode requirements on a QOS parameter register themselves to the 19 * User mode requests on a QOS parameter register themselves to the
20 * subsystem by opening the device node /dev/... and writing there request to 20 * subsystem by opening the device node /dev/... and writing there request to
21 * the node. As long as the process holds a file handle open to the node the 21 * the node. As long as the process holds a file handle open to the node the
22 * client continues to be accounted for. Upon file release the usermode 22 * client continues to be accounted for. Upon file release the usermode
23 * requirement is removed and a new qos target is computed. This way when the 23 * request is removed and a new qos target is computed. This way when the
24 * requirement that the application has is cleaned up when closes the file 24 * request that the application has is cleaned up when closes the file
25 * pointer or exits the pm_qos_object will get an opportunity to clean up. 25 * pointer or exits the pm_qos_object will get an opportunity to clean up.
26 * 26 *
27 * Mark Gross <mgross@linux.intel.com> 27 * Mark Gross <mgross@linux.intel.com>
28 */ 28 */
29 29
30/*#define DEBUG*/
31
30#include <linux/pm_qos_params.h> 32#include <linux/pm_qos_params.h>
31#include <linux/sched.h> 33#include <linux/sched.h>
32#include <linux/spinlock.h> 34#include <linux/spinlock.h>
@@ -42,25 +44,25 @@
42#include <linux/uaccess.h> 44#include <linux/uaccess.h>
43 45
44/* 46/*
45 * locking rule: all changes to requirements or notifiers lists 47 * locking rule: all changes to requests or notifiers lists
46 * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock 48 * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
47 * held, taken with _irqsave. One lock to rule them all 49 * held, taken with _irqsave. One lock to rule them all
48 */ 50 */
49struct requirement_list { 51struct pm_qos_request_list {
50 struct list_head list; 52 struct list_head list;
51 union { 53 union {
52 s32 value; 54 s32 value;
53 s32 usec; 55 s32 usec;
54 s32 kbps; 56 s32 kbps;
55 }; 57 };
56 char *name; 58 int pm_qos_class;
57}; 59};
58 60
59static s32 max_compare(s32 v1, s32 v2); 61static s32 max_compare(s32 v1, s32 v2);
60static s32 min_compare(s32 v1, s32 v2); 62static s32 min_compare(s32 v1, s32 v2);
61 63
62struct pm_qos_object { 64struct pm_qos_object {
63 struct requirement_list requirements; 65 struct pm_qos_request_list requests;
64 struct blocking_notifier_head *notifiers; 66 struct blocking_notifier_head *notifiers;
65 struct miscdevice pm_qos_power_miscdev; 67 struct miscdevice pm_qos_power_miscdev;
66 char *name; 68 char *name;
@@ -72,7 +74,7 @@ struct pm_qos_object {
72static struct pm_qos_object null_pm_qos; 74static struct pm_qos_object null_pm_qos;
73static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier); 75static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
74static struct pm_qos_object cpu_dma_pm_qos = { 76static struct pm_qos_object cpu_dma_pm_qos = {
75 .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)}, 77 .requests = {LIST_HEAD_INIT(cpu_dma_pm_qos.requests.list)},
76 .notifiers = &cpu_dma_lat_notifier, 78 .notifiers = &cpu_dma_lat_notifier,
77 .name = "cpu_dma_latency", 79 .name = "cpu_dma_latency",
78 .default_value = 2000 * USEC_PER_SEC, 80 .default_value = 2000 * USEC_PER_SEC,
@@ -82,7 +84,7 @@ static struct pm_qos_object cpu_dma_pm_qos = {
82 84
83static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); 85static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
84static struct pm_qos_object network_lat_pm_qos = { 86static struct pm_qos_object network_lat_pm_qos = {
85 .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)}, 87 .requests = {LIST_HEAD_INIT(network_lat_pm_qos.requests.list)},
86 .notifiers = &network_lat_notifier, 88 .notifiers = &network_lat_notifier,
87 .name = "network_latency", 89 .name = "network_latency",
88 .default_value = 2000 * USEC_PER_SEC, 90 .default_value = 2000 * USEC_PER_SEC,
@@ -93,8 +95,7 @@ static struct pm_qos_object network_lat_pm_qos = {
93 95
94static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier); 96static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
95static struct pm_qos_object network_throughput_pm_qos = { 97static struct pm_qos_object network_throughput_pm_qos = {
96 .requirements = 98 .requests = {LIST_HEAD_INIT(network_throughput_pm_qos.requests.list)},
97 {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
98 .notifiers = &network_throughput_notifier, 99 .notifiers = &network_throughput_notifier,
99 .name = "network_throughput", 100 .name = "network_throughput",
100 .default_value = 0, 101 .default_value = 0,
@@ -135,31 +136,34 @@ static s32 min_compare(s32 v1, s32 v2)
135} 136}
136 137
137 138
138static void update_target(int target) 139static void update_target(int pm_qos_class)
139{ 140{
140 s32 extreme_value; 141 s32 extreme_value;
141 struct requirement_list *node; 142 struct pm_qos_request_list *node;
142 unsigned long flags; 143 unsigned long flags;
143 int call_notifier = 0; 144 int call_notifier = 0;
144 145
145 spin_lock_irqsave(&pm_qos_lock, flags); 146 spin_lock_irqsave(&pm_qos_lock, flags);
146 extreme_value = pm_qos_array[target]->default_value; 147 extreme_value = pm_qos_array[pm_qos_class]->default_value;
147 list_for_each_entry(node, 148 list_for_each_entry(node,
148 &pm_qos_array[target]->requirements.list, list) { 149 &pm_qos_array[pm_qos_class]->requests.list, list) {
149 extreme_value = pm_qos_array[target]->comparitor( 150 extreme_value = pm_qos_array[pm_qos_class]->comparitor(
150 extreme_value, node->value); 151 extreme_value, node->value);
151 } 152 }
152 if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) { 153 if (atomic_read(&pm_qos_array[pm_qos_class]->target_value) !=
154 extreme_value) {
153 call_notifier = 1; 155 call_notifier = 1;
154 atomic_set(&pm_qos_array[target]->target_value, extreme_value); 156 atomic_set(&pm_qos_array[pm_qos_class]->target_value,
155 pr_debug(KERN_ERR "new target for qos %d is %d\n", target, 157 extreme_value);
156 atomic_read(&pm_qos_array[target]->target_value)); 158 pr_debug(KERN_ERR "new target for qos %d is %d\n", pm_qos_class,
159 atomic_read(&pm_qos_array[pm_qos_class]->target_value));
157 } 160 }
158 spin_unlock_irqrestore(&pm_qos_lock, flags); 161 spin_unlock_irqrestore(&pm_qos_lock, flags);
159 162
160 if (call_notifier) 163 if (call_notifier)
161 blocking_notifier_call_chain(pm_qos_array[target]->notifiers, 164 blocking_notifier_call_chain(
162 (unsigned long) extreme_value, NULL); 165 pm_qos_array[pm_qos_class]->notifiers,
166 (unsigned long) extreme_value, NULL);
163} 167}
164 168
165static int register_pm_qos_misc(struct pm_qos_object *qos) 169static int register_pm_qos_misc(struct pm_qos_object *qos)
@@ -185,125 +189,110 @@ static int find_pm_qos_object_by_minor(int minor)
185} 189}
186 190
187/** 191/**
188 * pm_qos_requirement - returns current system wide qos expectation 192 * pm_qos_request - returns current system wide qos expectation
189 * @pm_qos_class: identification of which qos value is requested 193 * @pm_qos_class: identification of which qos value is requested
190 * 194 *
191 * This function returns the current target value in an atomic manner. 195 * This function returns the current target value in an atomic manner.
192 */ 196 */
193int pm_qos_requirement(int pm_qos_class) 197int pm_qos_request(int pm_qos_class)
194{ 198{
195 return atomic_read(&pm_qos_array[pm_qos_class]->target_value); 199 return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
196} 200}
197EXPORT_SYMBOL_GPL(pm_qos_requirement); 201EXPORT_SYMBOL_GPL(pm_qos_request);
198 202
199/** 203/**
200 * pm_qos_add_requirement - inserts new qos request into the list 204 * pm_qos_add_request - inserts new qos request into the list
201 * @pm_qos_class: identifies which list of qos request to us 205 * @pm_qos_class: identifies which list of qos request to us
202 * @name: identifies the request
203 * @value: defines the qos request 206 * @value: defines the qos request
204 * 207 *
205 * This function inserts a new entry in the pm_qos_class list of requested qos 208 * This function inserts a new entry in the pm_qos_class list of requested qos
206 * performance characteristics. It recomputes the aggregate QoS expectations 209 * performance characteristics. It recomputes the aggregate QoS expectations
207 * for the pm_qos_class of parameters. 210 * for the pm_qos_class of parameters, and returns the pm_qos_request list
211 * element as a handle for use in updating and removal. Call needs to save
212 * this handle for later use.
208 */ 213 */
209int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value) 214struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value)
210{ 215{
211 struct requirement_list *dep; 216 struct pm_qos_request_list *dep;
212 unsigned long flags; 217 unsigned long flags;
213 218
214 dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL); 219 dep = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL);
215 if (dep) { 220 if (dep) {
216 if (value == PM_QOS_DEFAULT_VALUE) 221 if (value == PM_QOS_DEFAULT_VALUE)
217 dep->value = pm_qos_array[pm_qos_class]->default_value; 222 dep->value = pm_qos_array[pm_qos_class]->default_value;
218 else 223 else
219 dep->value = value; 224 dep->value = value;
220 dep->name = kstrdup(name, GFP_KERNEL); 225 dep->pm_qos_class = pm_qos_class;
221 if (!dep->name)
222 goto cleanup;
223 226
224 spin_lock_irqsave(&pm_qos_lock, flags); 227 spin_lock_irqsave(&pm_qos_lock, flags);
225 list_add(&dep->list, 228 list_add(&dep->list,
226 &pm_qos_array[pm_qos_class]->requirements.list); 229 &pm_qos_array[pm_qos_class]->requests.list);
227 spin_unlock_irqrestore(&pm_qos_lock, flags); 230 spin_unlock_irqrestore(&pm_qos_lock, flags);
228 update_target(pm_qos_class); 231 update_target(pm_qos_class);
229
230 return 0;
231 } 232 }
232 233
233cleanup: 234 return dep;
234 kfree(dep);
235 return -ENOMEM;
236} 235}
237EXPORT_SYMBOL_GPL(pm_qos_add_requirement); 236EXPORT_SYMBOL_GPL(pm_qos_add_request);
238 237
239/** 238/**
240 * pm_qos_update_requirement - modifies an existing qos request 239 * pm_qos_update_request - modifies an existing qos request
241 * @pm_qos_class: identifies which list of qos request to us 240 * @pm_qos_req : handle to list element holding a pm_qos request to use
242 * @name: identifies the request
243 * @value: defines the qos request 241 * @value: defines the qos request
244 * 242 *
245 * Updates an existing qos requirement for the pm_qos_class of parameters along 243 * Updates an existing qos request for the pm_qos_class of parameters along
246 * with updating the target pm_qos_class value. 244 * with updating the target pm_qos_class value.
247 * 245 *
248 * If the named request isn't in the list then no change is made. 246 * Attempts are made to make this code callable on hot code paths.
249 */ 247 */
250int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value) 248void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
249 s32 new_value)
251{ 250{
252 unsigned long flags; 251 unsigned long flags;
253 struct requirement_list *node;
254 int pending_update = 0; 252 int pending_update = 0;
253 s32 temp;
255 254
256 spin_lock_irqsave(&pm_qos_lock, flags); 255 spin_lock_irqsave(&pm_qos_lock, flags);
257 list_for_each_entry(node, 256 if (new_value == PM_QOS_DEFAULT_VALUE)
258 &pm_qos_array[pm_qos_class]->requirements.list, list) { 257 temp = pm_qos_array[pm_qos_req->pm_qos_class]->default_value;
259 if (strcmp(node->name, name) == 0) { 258 else
260 if (new_value == PM_QOS_DEFAULT_VALUE) 259 temp = new_value;
261 node->value = 260
262 pm_qos_array[pm_qos_class]->default_value; 261 if (temp != pm_qos_req->value) {
263 else 262 pending_update = 1;
264 node->value = new_value; 263 pm_qos_req->value = temp;
265 pending_update = 1;
266 break;
267 }
268 } 264 }
269 spin_unlock_irqrestore(&pm_qos_lock, flags); 265 spin_unlock_irqrestore(&pm_qos_lock, flags);
270 if (pending_update) 266 if (pending_update)
271 update_target(pm_qos_class); 267 update_target(pm_qos_req->pm_qos_class);
272
273 return 0;
274} 268}
275EXPORT_SYMBOL_GPL(pm_qos_update_requirement); 269EXPORT_SYMBOL_GPL(pm_qos_update_request);
276 270
277/** 271/**
278 * pm_qos_remove_requirement - modifies an existing qos request 272 * pm_qos_remove_request - modifies an existing qos request
279 * @pm_qos_class: identifies which list of qos request to us 273 * @pm_qos_req: handle to request list element
280 * @name: identifies the request
281 * 274 *
282 * Will remove named qos request from pm_qos_class list of parameters and 275 * Will remove pm qos request from the list of requests and
283 * recompute the current target value for the pm_qos_class. 276 * recompute the current target value for the pm_qos_class. Call this
277 * on slow code paths.
284 */ 278 */
285void pm_qos_remove_requirement(int pm_qos_class, char *name) 279void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
286{ 280{
287 unsigned long flags; 281 unsigned long flags;
288 struct requirement_list *node; 282 int qos_class;
289 int pending_update = 0; 283
284 if (pm_qos_req == NULL)
285 return;
286 /* silent return to keep pcm code cleaner */
290 287
288 qos_class = pm_qos_req->pm_qos_class;
291 spin_lock_irqsave(&pm_qos_lock, flags); 289 spin_lock_irqsave(&pm_qos_lock, flags);
292 list_for_each_entry(node, 290 list_del(&pm_qos_req->list);
293 &pm_qos_array[pm_qos_class]->requirements.list, list) { 291 kfree(pm_qos_req);
294 if (strcmp(node->name, name) == 0) {
295 kfree(node->name);
296 list_del(&node->list);
297 kfree(node);
298 pending_update = 1;
299 break;
300 }
301 }
302 spin_unlock_irqrestore(&pm_qos_lock, flags); 292 spin_unlock_irqrestore(&pm_qos_lock, flags);
303 if (pending_update) 293 update_target(qos_class);
304 update_target(pm_qos_class);
305} 294}
306EXPORT_SYMBOL_GPL(pm_qos_remove_requirement); 295EXPORT_SYMBOL_GPL(pm_qos_remove_request);
307 296
308/** 297/**
309 * pm_qos_add_notifier - sets notification entry for changes to target value 298 * pm_qos_add_notifier - sets notification entry for changes to target value
@@ -313,7 +302,7 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
313 * will register the notifier into a notification chain that gets called 302 * will register the notifier into a notification chain that gets called
314 * upon changes to the pm_qos_class target value. 303 * upon changes to the pm_qos_class target value.
315 */ 304 */
316 int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) 305int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
317{ 306{
318 int retval; 307 int retval;
319 308
@@ -343,21 +332,16 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
343} 332}
344EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); 333EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
345 334
346#define PID_NAME_LEN 32
347
348static int pm_qos_power_open(struct inode *inode, struct file *filp) 335static int pm_qos_power_open(struct inode *inode, struct file *filp)
349{ 336{
350 int ret;
351 long pm_qos_class; 337 long pm_qos_class;
352 char name[PID_NAME_LEN];
353 338
354 pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); 339 pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
355 if (pm_qos_class >= 0) { 340 if (pm_qos_class >= 0) {
356 filp->private_data = (void *)pm_qos_class; 341 filp->private_data = (void *) pm_qos_add_request(pm_qos_class,
357 snprintf(name, PID_NAME_LEN, "process_%d", current->pid); 342 PM_QOS_DEFAULT_VALUE);
358 ret = pm_qos_add_requirement(pm_qos_class, name, 343
359 PM_QOS_DEFAULT_VALUE); 344 if (filp->private_data)
360 if (ret >= 0)
361 return 0; 345 return 0;
362 } 346 }
363 return -EPERM; 347 return -EPERM;
@@ -365,32 +349,40 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
365 349
366static int pm_qos_power_release(struct inode *inode, struct file *filp) 350static int pm_qos_power_release(struct inode *inode, struct file *filp)
367{ 351{
368 int pm_qos_class; 352 struct pm_qos_request_list *req;
369 char name[PID_NAME_LEN];
370 353
371 pm_qos_class = (long)filp->private_data; 354 req = (struct pm_qos_request_list *)filp->private_data;
372 snprintf(name, PID_NAME_LEN, "process_%d", current->pid); 355 pm_qos_remove_request(req);
373 pm_qos_remove_requirement(pm_qos_class, name);
374 356
375 return 0; 357 return 0;
376} 358}
377 359
360
378static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, 361static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
379 size_t count, loff_t *f_pos) 362 size_t count, loff_t *f_pos)
380{ 363{
381 s32 value; 364 s32 value;
382 int pm_qos_class; 365 int x;
383 char name[PID_NAME_LEN]; 366 char ascii_value[11];
384 367 struct pm_qos_request_list *pm_qos_req;
385 pm_qos_class = (long)filp->private_data; 368
386 if (count != sizeof(s32)) 369 if (count == sizeof(s32)) {
370 if (copy_from_user(&value, buf, sizeof(s32)))
371 return -EFAULT;
372 } else if (count == 11) { /* len('0x12345678/0') */
373 if (copy_from_user(ascii_value, buf, 11))
374 return -EFAULT;
375 x = sscanf(ascii_value, "%x", &value);
376 if (x != 1)
377 return -EINVAL;
378 pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value);
379 } else
387 return -EINVAL; 380 return -EINVAL;
388 if (copy_from_user(&value, buf, sizeof(s32)))
389 return -EFAULT;
390 snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
391 pm_qos_update_requirement(pm_qos_class, name, value);
392 381
393 return sizeof(s32); 382 pm_qos_req = (struct pm_qos_request_list *)filp->private_data;
383 pm_qos_update_request(pm_qos_req, value);
384
385 return count;
394} 386}
395 387
396 388
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4aefa6dc3091..29de1965ff74 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -495,7 +495,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
495 s32 beaconint_us; 495 s32 beaconint_us;
496 496
497 if (latency < 0) 497 if (latency < 0)
498 latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY); 498 latency = pm_qos_request(PM_QOS_NETWORK_LATENCY);
499 499
500 beaconint_us = ieee80211_tu_to_usec( 500 beaconint_us = ieee80211_tu_to_usec(
501 found->vif.bss_conf.beacon_int); 501 found->vif.bss_conf.beacon_int);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 0d428d0896db..cbe815dfbdc8 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -648,9 +648,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
648 substream->number = idx; 648 substream->number = idx;
649 substream->stream = stream; 649 substream->stream = stream;
650 sprintf(substream->name, "subdevice #%i", idx); 650 sprintf(substream->name, "subdevice #%i", idx);
651 snprintf(substream->latency_id, sizeof(substream->latency_id),
652 "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
653 (stream ? 'c' : 'p'), idx);
654 substream->buffer_bytes_max = UINT_MAX; 651 substream->buffer_bytes_max = UINT_MAX;
655 if (prev == NULL) 652 if (prev == NULL)
656 pstr->substream = substream; 653 pstr->substream = substream;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 872887624030..605c86df71c5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -481,11 +481,13 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
481 snd_pcm_timer_resolution_change(substream); 481 snd_pcm_timer_resolution_change(substream);
482 runtime->status->state = SNDRV_PCM_STATE_SETUP; 482 runtime->status->state = SNDRV_PCM_STATE_SETUP;
483 483
484 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, 484 if (substream->latency_pm_qos_req) {
485 substream->latency_id); 485 pm_qos_remove_request(substream->latency_pm_qos_req);
486 substream->latency_pm_qos_req = NULL;
487 }
486 if ((usecs = period_to_usecs(runtime)) >= 0) 488 if ((usecs = period_to_usecs(runtime)) >= 0)
487 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, 489 substream->latency_pm_qos_req = pm_qos_add_request(
488 substream->latency_id, usecs); 490 PM_QOS_CPU_DMA_LATENCY, usecs);
489 return 0; 491 return 0;
490 _error: 492 _error:
491 /* hardware might be unuseable from this time, 493 /* hardware might be unuseable from this time,
@@ -540,8 +542,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
540 if (substream->ops->hw_free) 542 if (substream->ops->hw_free)
541 result = substream->ops->hw_free(substream); 543 result = substream->ops->hw_free(substream);
542 runtime->status->state = SNDRV_PCM_STATE_OPEN; 544 runtime->status->state = SNDRV_PCM_STATE_OPEN;
543 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, 545 pm_qos_remove_request(substream->latency_pm_qos_req);
544 substream->latency_id); 546 substream->latency_pm_qos_req = NULL;
545 return result; 547 return result;
546} 548}
547 549