Commit ed77134b authored by Mark Gross's avatar Mark Gross Committed by Rafael J. Wysocki

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: default avatarmarkgross <mgross@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 0fef8b1e
......@@ -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.
......
......@@ -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");
......
......@@ -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)) {
......
......@@ -182,7 +182,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;
......
......@@ -2524,12 +2524,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);
}
}
......@@ -2824,8 +2824,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 */
......@@ -2887,9 +2887,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
......
......@@ -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.";
......@@ -2899,7 +2900,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;
......@@ -2915,7 +2916,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);
......
......@@ -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);
......
......@@ -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>
......@@ -711,6 +712,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 */
......
......@@ -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);
......@@ -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;
......
This diff is collapsed.
......@@ -495,7 +495,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);
......
......@@ -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;
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment