On Sat, May 01, 2010 at 12:13:16AM +0200, Rafael J. Wysocki wrote: > On Friday 30 April 2010, mark gross wrote: > > The following is a refresh of the PM_QOS implementation, this patch > > updates some documentation input I got from Randy. > > > > 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.) > > > > I really would like to get this refresh taken care of. Its been taking > > me too long to close this. please review or include it in next. > > > > Thanks! > > Well, I'd take it to suspend-2.6/linux-next, but first, it touches > subsystems whose maintainers were not in the Cc list, like the network > drivers, wireless and ACPI. The changes are trivial, so I hope they don't > mind. > > Second, my tree is based on the Linus' tree rather than linux-next and > the change in net/mac80211/scan.c doesn't seem to match that. Please tell me > what I'm supposed to do about that. You can waite for monday and I'll send a rebased version to linus' tree. I thought linux-next was where folks wanted me to put it. I'll email out a new one monday. Thanks, --mgross > Thanks, > Rafael > > > > Ooops! forgot the signed off by line! > > > > Signed-off-by: mark gross <mgross@xxxxxxxxxxxxxxx> > > > > From c45d8d86f89ac55fbb9a499fbc754e35258bf818 Mon Sep 17 00:00:00 2001 > > From: mgross <mark.gross@xxxxxxxxx> > > Date: Sat, 13 Mar 2010 08:18:36 -0800 > > Subject: [PATCH 1/2] PM_QOS to use handle based list implementation and exported function name changes to be more descriptive of what is actually happening. > > > > --- > > Documentation/power/pm_qos_interface.txt | 48 ++++--- > > drivers/acpi/processor_idle.c | 2 +- > > drivers/cpuidle/governors/ladder.c | 2 +- > > drivers/cpuidle/governors/menu.c | 2 +- > > drivers/net/e1000e/netdev.c | 22 ++-- > > drivers/net/igbvf/netdev.c | 6 +- > > drivers/net/wireless/ipw2x00/ipw2100.c | 11 +- > > include/linux/netdevice.h | 4 + > > include/linux/pm_qos_params.h | 14 +- > > include/sound/pcm.h | 3 +- > > kernel/pm_qos_params.c | 214 ++++++++++++++--------------- > > net/mac80211/mlme.c | 2 +- > > net/mac80211/scan.c | 2 +- > > sound/core/pcm.c | 3 - > > sound/core/pcm_native.c | 14 +- > > 15 files changed, 177 insertions(+), 172 deletions(-) > > > > diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt > > index c40866e..bfed898 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 > > being runtime configurable or changeable from a driver was seen as too easy to > > abuse. > > > > -For each parameter a list of performance requirements is maintained along with > > +For each parameter a list of performance requests is maintained along with > > an aggregated target value. The aggregated target value is updated with > > -changes to the requirement list or elements of the list. Typically the > > -aggregated target value is simply the max or min of the requirement values held > > +changes to the request list or elements of the list. Typically the > > +aggregated target value is simply the max or min of the request values held > > in the parameter list elements. > > > > From kernel mode the use of this interface is simple: > > -pm_qos_add_requirement(param_id, name, target_value): > > -Will insert a named element in the list for that identified PM_QOS parameter > > -with the target value. Upon change to this list the new target is recomputed > > -and any registered notifiers are called only if the target value is now > > -different. > > > > -pm_qos_update_requirement(param_id, name, new_target_value): > > -Will search the list identified by the param_id for the named list element and > > -then update its target value, calling the notification tree if the aggregated > > -target is changed. with that name is already registered. > > +handle = pm_qos_add_request(param_class, target_value): > > +Will insert an element into the list for that identified PM_QOS class with the > > +target value. Upon change to this list the new target is recomputed and any > > +registered notifiers are called only if the target value is now different. > > +Clients of pm_qos need to save the returned handle. > > > > -pm_qos_remove_requirement(param_id, name): > > -Will search the identified list for the named element and remove it, after > > -removal it will update the aggregate target and call the notification tree if > > -the target was changed as a result of removing the named requirement. > > +void pm_qos_update_request(handle, new_target_value): > > +Will update the list element pointed to by the handle with the new target value > > +and recompute the new aggregated target, calling the notification tree if the > > +target is changed. > > + > > +void pm_qos_remove_request(handle): > > +Will remove the element. After removal it will update the aggregate target and > > +call the notification tree if the target was changed as a result of removing > > +the request. > > > > > > From user mode: > > -Only processes can register a pm_qos requirement. To provide for automatic > > -cleanup for process the interface requires the process to register its > > -parameter requirements in the following way: > > +Only processes can register a pm_qos request. To provide for automatic > > +cleanup of a process, the interface requires the process to register its > > +parameter requests in the following way: > > > > To register the default pm_qos target for the specific parameter, the process > > must open one of /dev/[cpu_dma_latency, network_latency, network_throughput] > > > > As long as the device node is held open that process has a registered > > -requirement on the parameter. The name of the requirement is "process_<PID>" > > -derived from the current->pid from within the open system call. > > +request on the parameter. > > > > -To change the requested target value the process needs to write a s32 value to > > -the open device node. This translates to a pm_qos_update_requirement call. > > +To change the requested target value the process needs to write an s32 value to > > +the open device node. Alternatively the user mode program could write a hex > > +string for the value using 10 char long format e.g. "0x12345678". This > > +translates to a pm_qos_update_request call. > > > > To remove the user mode request for a target value simply close the device > > node. > > diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c > > index 5939e7f..c3817e1 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) > > "max_cstate: C%d\n" > > "maximum allowed latency: %d usec\n", > > pr->power.state ? pr->power.state - pr->power.states : 0, > > - max_cstate, pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)); > > + max_cstate, pm_qos_request(PM_QOS_CPU_DMA_LATENCY)); > > > > seq_puts(seq, "states:\n"); > > > > diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c > > index 1c1ceb4..12c9890 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) > > struct ladder_device *ldev = &__get_cpu_var(ladder_devices); > > struct ladder_device_state *last_state; > > int last_residency, last_idx = ldev->last_state_idx; > > - int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); > > + int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); > > > > /* Special case when user has set very strict latency requirement */ > > if (unlikely(latency_req == 0)) { > > diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c > > index 1aea715..61ca939 100644 > > --- a/drivers/cpuidle/governors/menu.c > > +++ b/drivers/cpuidle/governors/menu.c > > @@ -183,7 +183,7 @@ static u64 div_round64(u64 dividend, u32 divisor) > > static int menu_select(struct cpuidle_device *dev) > > { > > struct menu_device *data = &__get_cpu_var(menu_devices); > > - int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); > > + int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); > > int i; > > int multiplier; > > > > diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c > > index 904bd6b..7550879 100644 > > --- a/drivers/net/e1000e/netdev.c > > +++ b/drivers/net/e1000e/netdev.c > > @@ -2882,12 +2882,12 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) > > * excessive C-state transition latencies result in > > * dropped transactions. > > */ > > - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, > > - adapter->netdev->name, 55); > > + pm_qos_update_request( > > + adapter->netdev->pm_qos_req, 55); > > } else { > > - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, > > - adapter->netdev->name, > > - PM_QOS_DEFAULT_VALUE); > > + pm_qos_update_request( > > + adapter->netdev->pm_qos_req, > > + PM_QOS_DEFAULT_VALUE); > > } > > } > > > > @@ -3181,8 +3181,8 @@ int e1000e_up(struct e1000_adapter *adapter) > > > > /* DMA latency requirement to workaround early-receive/jumbo issue */ > > if (adapter->flags & FLAG_HAS_ERT) > > - pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, > > - adapter->netdev->name, > > + adapter->netdev->pm_qos_req = > > + pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, > > PM_QOS_DEFAULT_VALUE); > > > > /* hardware has been reset, we need to reload some things */ > > @@ -3244,9 +3244,11 @@ void e1000e_down(struct e1000_adapter *adapter) > > e1000_clean_tx_ring(adapter); > > e1000_clean_rx_ring(adapter); > > > > - if (adapter->flags & FLAG_HAS_ERT) > > - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, > > - adapter->netdev->name); > > + if (adapter->flags & FLAG_HAS_ERT) { > > + pm_qos_remove_request( > > + adapter->netdev->pm_qos_req); > > + adapter->netdev->pm_qos_req = NULL; > > + } > > > > /* > > * 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 7012e3d..5e2b2a8 100644 > > --- a/drivers/net/igbvf/netdev.c > > +++ b/drivers/net/igbvf/netdev.c > > @@ -48,6 +48,7 @@ > > #define DRV_VERSION "1.0.0-k0" > > char igbvf_driver_name[] = "igbvf"; > > const char igbvf_driver_version[] = DRV_VERSION; > > +struct pm_qos_request_list *igbvf_driver_pm_qos_req; > > static const char igbvf_driver_string[] = > > "Intel(R) Virtual Function Network Driver"; > > static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation."; > > @@ -2901,7 +2902,7 @@ static int __init igbvf_init_module(void) > > printk(KERN_INFO "%s\n", igbvf_copyright); > > > > ret = pci_register_driver(&igbvf_driver); > > - pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name, > > + igbvf_driver_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, > > PM_QOS_DEFAULT_VALUE); > > > > return ret; > > @@ -2917,7 +2918,8 @@ module_init(igbvf_init_module); > > static void __exit igbvf_exit_module(void) > > { > > pci_unregister_driver(&igbvf_driver); > > - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name); > > + pm_qos_remove_request(igbvf_driver_pm_qos_req); > > + igbvf_driver_pm_qos_req = NULL; > > } > > module_exit(igbvf_exit_module); > > > > diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c > > index 2088ac0..7040e3b 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. > > #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" > > #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" > > > > +struct pm_qos_request_list *ipw2100_pm_qos_req; > > + > > /* Debugging stuff */ > > #ifdef CONFIG_IPW2100_DEBUG > > #define IPW2100_RX_DEBUG /* Reception debugging */ > > @@ -1739,7 +1741,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) > > /* the ipw2100 hardware really doesn't want power management delays > > * longer than 175usec > > */ > > - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175); > > + pm_qos_update_request(ipw2100_pm_qos_req, 175); > > > > /* If the interrupt is enabled, turn it off... */ > > spin_lock_irqsave(&priv->low_lock, flags); > > @@ -1887,8 +1889,7 @@ static void ipw2100_down(struct ipw2100_priv *priv) > > ipw2100_disable_interrupts(priv); > > spin_unlock_irqrestore(&priv->low_lock, flags); > > > > - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", > > - PM_QOS_DEFAULT_VALUE); > > + pm_qos_update_request(ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE); > > > > /* We have to signal any supplicant if we are disassociating */ > > if (associated) > > @@ -6669,7 +6670,7 @@ static int __init ipw2100_init(void) > > if (ret) > > goto out; > > > > - pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", > > + ipw2100_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, > > PM_QOS_DEFAULT_VALUE); > > #ifdef CONFIG_IPW2100_DEBUG > > ipw2100_debug_level = debug; > > @@ -6692,7 +6693,7 @@ static void __exit ipw2100_exit(void) > > &driver_attr_debug_level); > > #endif > > pci_unregister_driver(&ipw2100_pci_driver); > > - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100"); > > + pm_qos_remove_request(ipw2100_pm_qos_req); > > } > > > > module_init(ipw2100_init); > > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h > > index 40d4c20..5dd6d8c 100644 > > --- a/include/linux/netdevice.h > > +++ b/include/linux/netdevice.h > > @@ -31,6 +31,7 @@ > > #include <linux/if_link.h> > > > > #ifdef __KERNEL__ > > +#include <linux/pm_qos_params.h> > > #include <linux/timer.h> > > #include <linux/delay.h> > > #include <linux/mm.h> > > @@ -778,6 +779,9 @@ struct net_device { > > * the interface. > > */ > > char name[IFNAMSIZ]; > > + > > + struct pm_qos_request_list *pm_qos_req; > > + > > /* device name hash chain */ > > struct hlist_node name_hlist; > > /* snmp alias */ > > diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h > > index d74f75e..8ba440e 100644 > > --- a/include/linux/pm_qos_params.h > > +++ b/include/linux/pm_qos_params.h > > @@ -14,12 +14,14 @@ > > #define PM_QOS_NUM_CLASSES 4 > > #define PM_QOS_DEFAULT_VALUE -1 > > > > -int pm_qos_add_requirement(int qos, char *name, s32 value); > > -int pm_qos_update_requirement(int qos, char *name, s32 new_value); > > -void pm_qos_remove_requirement(int qos, char *name); > > +struct pm_qos_request_list; > > > > -int pm_qos_requirement(int qos); > > +struct pm_qos_request_list *pm_qos_add_request(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_add_notifier(int qos, struct notifier_block *notifier); > > -int pm_qos_remove_notifier(int qos, struct notifier_block *notifier); > > +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); > > > > diff --git a/include/sound/pcm.h b/include/sound/pcm.h > > index 8b611a5..dd76cde 100644 > > --- a/include/sound/pcm.h > > +++ b/include/sound/pcm.h > > @@ -29,6 +29,7 @@ > > #include <linux/poll.h> > > #include <linux/mm.h> > > #include <linux/bitops.h> > > +#include <linux/pm_qos_params.h> > > > > #define snd_pcm_substream_chip(substream) ((substream)->private_data) > > #define snd_pcm_chip(pcm) ((pcm)->private_data) > > @@ -365,7 +366,7 @@ struct snd_pcm_substream { > > int number; > > char name[32]; /* substream name */ > > int stream; /* stream (direction) */ > > - char latency_id[20]; /* latency identifier */ > > + struct pm_qos_request_list *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_params.c b/kernel/pm_qos_params.c > > index 3db49b9..a1aea04 100644 > > --- a/kernel/pm_qos_params.c > > +++ b/kernel/pm_qos_params.c > > @@ -2,7 +2,7 @@ > > * This module exposes the interface to kernel space for specifying > > * QoS dependencies. It provides infrastructure for registration of: > > * > > - * Dependents on a QoS value : register requirements > > + * 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. > > @@ -14,19 +14,21 @@ > > * timeout: usec <-- currently not used. > > * throughput: kbs (kilo byte / sec) > > * > > - * There are lists of pm_qos_objects each one wrapping requirements, notifiers > > + * There are lists of pm_qos_objects each one wrapping requests, notifiers > > * > > - * User mode requirements on a QOS parameter register themselves to the > > + * 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 > > - * requirement is removed and a new qos target is computed. This way when the > > - * requirement that the application has is cleaned up when closes the file > > + * 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@xxxxxxxxxxxxxxx> > > */ > > > > +/*#define DEBUG*/ > > + > > #include <linux/pm_qos_params.h> > > #include <linux/sched.h> > > #include <linux/spinlock.h> > > @@ -42,25 +44,25 @@ > > #include <linux/uaccess.h> > > > > /* > > - * locking rule: all changes to requirements or notifiers lists > > + * 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 > > */ > > -struct requirement_list { > > +struct pm_qos_request_list { > > struct list_head list; > > union { > > s32 value; > > s32 usec; > > s32 kbps; > > }; > > - char *name; > > + int pm_qos_class; > > }; > > > > static s32 max_compare(s32 v1, s32 v2); > > static s32 min_compare(s32 v1, s32 v2); > > > > struct pm_qos_object { > > - struct requirement_list requirements; > > + struct pm_qos_request_list requests; > > struct blocking_notifier_head *notifiers; > > struct miscdevice pm_qos_power_miscdev; > > char *name; > > @@ -72,7 +74,7 @@ struct pm_qos_object { > > 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 = { > > - .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)}, > > + .requests = {LIST_HEAD_INIT(cpu_dma_pm_qos.requests.list)}, > > .notifiers = &cpu_dma_lat_notifier, > > .name = "cpu_dma_latency", > > .default_value = 2000 * USEC_PER_SEC, > > @@ -82,7 +84,7 @@ static struct pm_qos_object cpu_dma_pm_qos = { > > > > static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); > > static struct pm_qos_object network_lat_pm_qos = { > > - .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)}, > > + .requests = {LIST_HEAD_INIT(network_lat_pm_qos.requests.list)}, > > .notifiers = &network_lat_notifier, > > .name = "network_latency", > > .default_value = 2000 * USEC_PER_SEC, > > @@ -93,8 +95,7 @@ static struct pm_qos_object network_lat_pm_qos = { > > > > static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier); > > static struct pm_qos_object network_throughput_pm_qos = { > > - .requirements = > > - {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)}, > > + .requests = {LIST_HEAD_INIT(network_throughput_pm_qos.requests.list)}, > > .notifiers = &network_throughput_notifier, > > .name = "network_throughput", > > .default_value = 0, > > @@ -135,31 +136,34 @@ static s32 min_compare(s32 v1, s32 v2) > > } > > > > > > -static void update_target(int target) > > +static void update_target(int pm_qos_class) > > { > > s32 extreme_value; > > - struct requirement_list *node; > > + struct pm_qos_request_list *node; > > unsigned long flags; > > int call_notifier = 0; > > > > spin_lock_irqsave(&pm_qos_lock, flags); > > - extreme_value = pm_qos_array[target]->default_value; > > + extreme_value = pm_qos_array[pm_qos_class]->default_value; > > list_for_each_entry(node, > > - &pm_qos_array[target]->requirements.list, list) { > > - extreme_value = pm_qos_array[target]->comparitor( > > + &pm_qos_array[pm_qos_class]->requests.list, list) { > > + extreme_value = pm_qos_array[pm_qos_class]->comparitor( > > extreme_value, node->value); > > } > > - if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) { > > + if (atomic_read(&pm_qos_array[pm_qos_class]->target_value) != > > + extreme_value) { > > call_notifier = 1; > > - atomic_set(&pm_qos_array[target]->target_value, extreme_value); > > - pr_debug(KERN_ERR "new target for qos %d is %d\n", target, > > - atomic_read(&pm_qos_array[target]->target_value)); > > + atomic_set(&pm_qos_array[pm_qos_class]->target_value, > > + extreme_value); > > + pr_debug(KERN_ERR "new target for qos %d is %d\n", pm_qos_class, > > + atomic_read(&pm_qos_array[pm_qos_class]->target_value)); > > } > > spin_unlock_irqrestore(&pm_qos_lock, flags); > > > > if (call_notifier) > > - blocking_notifier_call_chain(pm_qos_array[target]->notifiers, > > - (unsigned long) extreme_value, NULL); > > + blocking_notifier_call_chain( > > + pm_qos_array[pm_qos_class]->notifiers, > > + (unsigned long) extreme_value, NULL); > > } > > > > static int register_pm_qos_misc(struct pm_qos_object *qos) > > @@ -185,125 +189,110 @@ static int find_pm_qos_object_by_minor(int minor) > > } > > > > /** > > - * pm_qos_requirement - returns current system wide qos expectation > > + * 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 in an atomic manner. > > */ > > -int pm_qos_requirement(int pm_qos_class) > > +int pm_qos_request(int pm_qos_class) > > { > > return atomic_read(&pm_qos_array[pm_qos_class]->target_value); > > } > > -EXPORT_SYMBOL_GPL(pm_qos_requirement); > > +EXPORT_SYMBOL_GPL(pm_qos_request); > > > > /** > > - * pm_qos_add_requirement - inserts new qos request into the list > > + * pm_qos_add_request - inserts new qos request into the list > > * @pm_qos_class: identifies which list of qos request to us > > - * @name: identifies the request > > * @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. > > + * for the pm_qos_class of parameters, and returns the pm_qos_request list > > + * element as a handle for use in updating and removal. Call needs to save > > + * this handle for later use. > > */ > > -int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value) > > +struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value) > > { > > - struct requirement_list *dep; > > + struct pm_qos_request_list *dep; > > unsigned long flags; > > > > - dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL); > > + dep = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL); > > if (dep) { > > if (value == PM_QOS_DEFAULT_VALUE) > > dep->value = pm_qos_array[pm_qos_class]->default_value; > > else > > dep->value = value; > > - dep->name = kstrdup(name, GFP_KERNEL); > > - if (!dep->name) > > - goto cleanup; > > + dep->pm_qos_class = pm_qos_class; > > > > spin_lock_irqsave(&pm_qos_lock, flags); > > list_add(&dep->list, > > - &pm_qos_array[pm_qos_class]->requirements.list); > > + &pm_qos_array[pm_qos_class]->requests.list); > > spin_unlock_irqrestore(&pm_qos_lock, flags); > > update_target(pm_qos_class); > > - > > - return 0; > > } > > > > -cleanup: > > - kfree(dep); > > - return -ENOMEM; > > + return dep; > > } > > -EXPORT_SYMBOL_GPL(pm_qos_add_requirement); > > +EXPORT_SYMBOL_GPL(pm_qos_add_request); > > > > /** > > - * pm_qos_update_requirement - modifies an existing qos request > > - * @pm_qos_class: identifies which list of qos request to us > > - * @name: identifies the 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 requirement for the pm_qos_class of parameters along > > + * Updates an existing qos request for the pm_qos_class of parameters along > > * with updating the target pm_qos_class value. > > * > > - * If the named request isn't in the list then no change is made. > > + * Attempts are made to make this code callable on hot code paths. > > */ > > -int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value) > > +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req, > > + s32 new_value) > > { > > unsigned long flags; > > - struct requirement_list *node; > > int pending_update = 0; > > + s32 temp; > > > > spin_lock_irqsave(&pm_qos_lock, flags); > > - list_for_each_entry(node, > > - &pm_qos_array[pm_qos_class]->requirements.list, list) { > > - if (strcmp(node->name, name) == 0) { > > - if (new_value == PM_QOS_DEFAULT_VALUE) > > - node->value = > > - pm_qos_array[pm_qos_class]->default_value; > > - else > > - node->value = new_value; > > - pending_update = 1; > > - break; > > - } > > + if (new_value == PM_QOS_DEFAULT_VALUE) > > + temp = pm_qos_array[pm_qos_req->pm_qos_class]->default_value; > > + else > > + temp = new_value; > > + > > + if (temp != pm_qos_req->value) { > > + pending_update = 1; > > + pm_qos_req->value = temp; > > } > > spin_unlock_irqrestore(&pm_qos_lock, flags); > > if (pending_update) > > - update_target(pm_qos_class); > > - > > - return 0; > > + update_target(pm_qos_req->pm_qos_class); > > } > > -EXPORT_SYMBOL_GPL(pm_qos_update_requirement); > > +EXPORT_SYMBOL_GPL(pm_qos_update_request); > > > > /** > > - * pm_qos_remove_requirement - modifies an existing qos request > > - * @pm_qos_class: identifies which list of qos request to us > > - * @name: identifies the request > > + * pm_qos_remove_request - modifies an existing qos request > > + * @pm_qos_req: handle to request list element > > * > > - * Will remove named qos request from pm_qos_class list of parameters and > > - * recompute the current target value for the pm_qos_class. > > + * 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_requirement(int pm_qos_class, char *name) > > +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req) > > { > > unsigned long flags; > > - struct requirement_list *node; > > - int pending_update = 0; > > + int qos_class; > > + > > + if (pm_qos_req == NULL) > > + return; > > + /* silent return to keep pcm code cleaner */ > > > > + qos_class = pm_qos_req->pm_qos_class; > > spin_lock_irqsave(&pm_qos_lock, flags); > > - list_for_each_entry(node, > > - &pm_qos_array[pm_qos_class]->requirements.list, list) { > > - if (strcmp(node->name, name) == 0) { > > - kfree(node->name); > > - list_del(&node->list); > > - kfree(node); > > - pending_update = 1; > > - break; > > - } > > - } > > + list_del(&pm_qos_req->list); > > + kfree(pm_qos_req); > > spin_unlock_irqrestore(&pm_qos_lock, flags); > > - if (pending_update) > > - update_target(pm_qos_class); > > + update_target(qos_class); > > } > > -EXPORT_SYMBOL_GPL(pm_qos_remove_requirement); > > +EXPORT_SYMBOL_GPL(pm_qos_remove_request); > > > > /** > > * pm_qos_add_notifier - sets notification entry for changes to target value > > @@ -313,7 +302,7 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_requirement); > > * 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 pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) > > { > > int retval; > > > > @@ -343,21 +332,16 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) > > } > > EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); > > > > -#define PID_NAME_LEN 32 > > - > > static int pm_qos_power_open(struct inode *inode, struct file *filp) > > { > > - int ret; > > long pm_qos_class; > > - char name[PID_NAME_LEN]; > > > > pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); > > if (pm_qos_class >= 0) { > > - filp->private_data = (void *)pm_qos_class; > > - snprintf(name, PID_NAME_LEN, "process_%d", current->pid); > > - ret = pm_qos_add_requirement(pm_qos_class, name, > > - PM_QOS_DEFAULT_VALUE); > > - if (ret >= 0) > > + filp->private_data = (void *) pm_qos_add_request(pm_qos_class, > > + PM_QOS_DEFAULT_VALUE); > > + > > + if (filp->private_data) > > return 0; > > } > > return -EPERM; > > @@ -365,32 +349,40 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp) > > > > static int pm_qos_power_release(struct inode *inode, struct file *filp) > > { > > - int pm_qos_class; > > - char name[PID_NAME_LEN]; > > + struct pm_qos_request_list *req; > > > > - pm_qos_class = (long)filp->private_data; > > - snprintf(name, PID_NAME_LEN, "process_%d", current->pid); > > - pm_qos_remove_requirement(pm_qos_class, name); > > + req = (struct pm_qos_request_list *)filp->private_data; > > + pm_qos_remove_request(req); > > > > return 0; > > } > > > > + > > static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, > > size_t count, loff_t *f_pos) > > { > > s32 value; > > - int pm_qos_class; > > - char name[PID_NAME_LEN]; > > - > > - pm_qos_class = (long)filp->private_data; > > - if (count != sizeof(s32)) > > + int x; > > + char ascii_value[11]; > > + 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) { /* len('0x12345678/0') */ > > + if (copy_from_user(ascii_value, buf, 11)) > > + return -EFAULT; > > + x = sscanf(ascii_value, "%x", &value); > > + if (x != 1) > > + return -EINVAL; > > + pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value); > > + } else > > return -EINVAL; > > - if (copy_from_user(&value, buf, sizeof(s32))) > > - return -EFAULT; > > - snprintf(name, PID_NAME_LEN, "process_%d", current->pid); > > - pm_qos_update_requirement(pm_qos_class, name, value); > > > > - return sizeof(s32); > > + pm_qos_req = (struct pm_qos_request_list *)filp->private_data; > > + pm_qos_update_request(pm_qos_req, value); > > + > > + return count; > > } > > > > > > diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c > > index 358226f..3deaac3 100644 > > --- a/net/mac80211/mlme.c > > +++ b/net/mac80211/mlme.c > > @@ -507,7 +507,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) > > s32 beaconint_us; > > > > if (latency < 0) > > - latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY); > > + latency = pm_qos_request(PM_QOS_NETWORK_LATENCY); > > > > beaconint_us = ieee80211_tu_to_usec( > > found->vif.bss_conf.beacon_int); > > diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c > > index 8bc961f..be52bb8 100644 > > --- a/net/mac80211/scan.c > > +++ b/net/mac80211/scan.c > > @@ -510,7 +510,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, > > bad_latency = time_after(jiffies + > > ieee80211_scan_get_channel_time(next_chan), > > local->leave_oper_channel_time + > > - usecs_to_jiffies(pm_qos_requirement(PM_QOS_NETWORK_LATENCY))); > > + usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY))); > > > > listen_int_exceeded = time_after(jiffies + > > ieee80211_scan_get_channel_time(next_chan), > > diff --git a/sound/core/pcm.c b/sound/core/pcm.c > > index 0d428d0..cbe815d 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) > > substream->number = idx; > > substream->stream = stream; > > sprintf(substream->name, "subdevice #%i", idx); > > - snprintf(substream->latency_id, sizeof(substream->latency_id), > > - "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device, > > - (stream ? 'c' : 'p'), idx); > > substream->buffer_bytes_max = UINT_MAX; > > if (prev == NULL) > > pstr->substream = substream; > > diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c > > index c22ebb0..1bb0e23 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, > > snd_pcm_timer_resolution_change(substream); > > runtime->status->state = SNDRV_PCM_STATE_SETUP; > > > > - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, > > - substream->latency_id); > > + if (substream->latency_pm_qos_req) { > > + pm_qos_remove_request(substream->latency_pm_qos_req); > > + substream->latency_pm_qos_req = NULL; > > + } > > if ((usecs = period_to_usecs(runtime)) >= 0) > > - pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, > > - substream->latency_id, usecs); > > + substream->latency_pm_qos_req = pm_qos_add_request( > > + PM_QOS_CPU_DMA_LATENCY, usecs); > > return 0; > > _error: > > /* hardware might be unuseable from this time, > > @@ -540,8 +542,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) > > if (substream->ops->hw_free) > > result = substream->ops->hw_free(substream); > > runtime->status->state = SNDRV_PCM_STATE_OPEN; > > - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, > > - substream->latency_id); > > + pm_qos_remove_request(substream->latency_pm_qos_req); > > + substream->latency_pm_qos_req = NULL; > > return result; > > } > > > > _______________________________________________ linux-pm mailing list linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/linux-pm