pm_qos_requirement might sleep
Make PM_QOS and CPU_IDLE play nicer when run with the RT-Preempt kernel. The purpose of the patch is to remove the spin_lock around the read in the function pm_qos_requirement - since spinlocks can sleep in -rt and this function is called from idle. CPU_IDLE polls the target_value's of some of the pm_qos parameters from the idle loop causing sleeping locking warnings. Changing the target_value to an atomic avoids this issue. Remove the spinlock in pm_qos_requirement by making target_value an atomic type. Signed-off-by: mark gross <mgross@linux.intel.com> Signed-off-by: John Kacur <jkacur@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
74c4633da7
Коммит
9d35935747
|
@ -43,7 +43,7 @@
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* locking rule: all changes to target_value or requirements or notifiers lists
|
* locking rule: all changes to requirements or notifiers lists
|
||||||
* or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
|
* 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
|
* held, taken with _irqsave. One lock to rule them all
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +66,7 @@ struct pm_qos_object {
|
||||||
struct miscdevice pm_qos_power_miscdev;
|
struct miscdevice pm_qos_power_miscdev;
|
||||||
char *name;
|
char *name;
|
||||||
s32 default_value;
|
s32 default_value;
|
||||||
s32 target_value;
|
atomic_t target_value;
|
||||||
s32 (*comparitor)(s32, s32);
|
s32 (*comparitor)(s32, s32);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ static struct pm_qos_object cpu_dma_pm_qos = {
|
||||||
.notifiers = &cpu_dma_lat_notifier,
|
.notifiers = &cpu_dma_lat_notifier,
|
||||||
.name = "cpu_dma_latency",
|
.name = "cpu_dma_latency",
|
||||||
.default_value = 2000 * USEC_PER_SEC,
|
.default_value = 2000 * USEC_PER_SEC,
|
||||||
.target_value = 2000 * USEC_PER_SEC,
|
.target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
|
||||||
.comparitor = min_compare
|
.comparitor = min_compare
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ static struct pm_qos_object network_lat_pm_qos = {
|
||||||
.notifiers = &network_lat_notifier,
|
.notifiers = &network_lat_notifier,
|
||||||
.name = "network_latency",
|
.name = "network_latency",
|
||||||
.default_value = 2000 * USEC_PER_SEC,
|
.default_value = 2000 * USEC_PER_SEC,
|
||||||
.target_value = 2000 * USEC_PER_SEC,
|
.target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
|
||||||
.comparitor = min_compare
|
.comparitor = min_compare
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ static struct pm_qos_object network_throughput_pm_qos = {
|
||||||
.notifiers = &network_throughput_notifier,
|
.notifiers = &network_throughput_notifier,
|
||||||
.name = "network_throughput",
|
.name = "network_throughput",
|
||||||
.default_value = 0,
|
.default_value = 0,
|
||||||
.target_value = 0,
|
.target_value = ATOMIC_INIT(0),
|
||||||
.comparitor = max_compare
|
.comparitor = max_compare
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,11 +150,11 @@ static void update_target(int target)
|
||||||
extreme_value = pm_qos_array[target]->comparitor(
|
extreme_value = pm_qos_array[target]->comparitor(
|
||||||
extreme_value, node->value);
|
extreme_value, node->value);
|
||||||
}
|
}
|
||||||
if (pm_qos_array[target]->target_value != extreme_value) {
|
if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) {
|
||||||
call_notifier = 1;
|
call_notifier = 1;
|
||||||
pm_qos_array[target]->target_value = extreme_value;
|
atomic_set(&pm_qos_array[target]->target_value, extreme_value);
|
||||||
pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
|
pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
|
||||||
pm_qos_array[target]->target_value);
|
atomic_read(&pm_qos_array[target]->target_value));
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&pm_qos_lock, flags);
|
spin_unlock_irqrestore(&pm_qos_lock, flags);
|
||||||
|
|
||||||
|
@ -193,14 +193,7 @@ static int find_pm_qos_object_by_minor(int minor)
|
||||||
*/
|
*/
|
||||||
int pm_qos_requirement(int pm_qos_class)
|
int pm_qos_requirement(int pm_qos_class)
|
||||||
{
|
{
|
||||||
int ret_val;
|
return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&pm_qos_lock, flags);
|
|
||||||
ret_val = pm_qos_array[pm_qos_class]->target_value;
|
|
||||||
spin_unlock_irqrestore(&pm_qos_lock, flags);
|
|
||||||
|
|
||||||
return ret_val;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pm_qos_requirement);
|
EXPORT_SYMBOL_GPL(pm_qos_requirement);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче