pm_qos_requirement-fix Add a raw_spinlock_t for target. target is modified in pm_qos_requirement called by idle so it cannot be allowed to sleep. Signed-off-by: John Kacur Signed-off-by: mark gross Index: linux-2.6.26.1-rt1.jk/kernel/pm_qos_params.c =================================================================== --- linux-2.6.26.1-rt1.jk.orig/kernel/pm_qos_params.c +++ linux-2.6.26.1-rt1.jk/kernel/pm_qos_params.c @@ -42,9 +42,10 @@ #include /* - * 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 - * held, taken with _irqsave. One lock to rule them all + * held, taken with _irqsave. target is locked by pm_qos_rawlock because it + * is modified in pm_qos_requirement called from idle and cannot sleep. */ struct requirement_list { struct list_head list; @@ -111,6 +112,7 @@ static struct pm_qos_object *pm_qos_arra }; static DEFINE_SPINLOCK(pm_qos_lock); +static DEFINE_RAW_SPINLOCK(pm_qos_rawlock); static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); @@ -149,13 +151,15 @@ static void update_target(int target) extreme_value = pm_qos_array[target]->comparitor( extreme_value, node->value); } + spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_lock_irqsave(&pm_qos_rawlock, flags); if (pm_qos_array[target]->target_value != extreme_value) { call_notifier = 1; pm_qos_array[target]->target_value = extreme_value; pr_debug(KERN_ERR "new target for qos %d is %d\n", target, pm_qos_array[target]->target_value); } - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock_irqrestore(&pm_qos_rawlock, flags); if (call_notifier) blocking_notifier_call_chain(pm_qos_array[target]->notifiers, @@ -195,9 +199,12 @@ int pm_qos_requirement(int pm_qos_class) int ret_val; unsigned long flags; - spin_lock_irqsave(&pm_qos_lock, flags); + /* + * pm_qos_requirement is called from idle, so it cannot sleep + */ + spin_lock_irqsave(&pm_qos_rawlock, flags); ret_val = pm_qos_array[pm_qos_class]->target_value; - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock_irqrestore(&pm_qos_rawlock, flags); return ret_val; }