diff options
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 24 | ||||
-rw-r--r-- | include/linux/cpu.h | 5 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/cpu.c | 33 |
4 files changed, 49 insertions, 14 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 25acf478c9e8..23a63207d747 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -38,7 +38,6 @@ static struct cpufreq_driver *cpufreq_driver; | |||
38 | static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; | 38 | static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; |
39 | static DEFINE_SPINLOCK(cpufreq_driver_lock); | 39 | static DEFINE_SPINLOCK(cpufreq_driver_lock); |
40 | 40 | ||
41 | |||
42 | /* internal prototypes */ | 41 | /* internal prototypes */ |
43 | static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); | 42 | static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); |
44 | static void handle_update(void *data); | 43 | static void handle_update(void *data); |
@@ -1115,24 +1114,21 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, | |||
1115 | int retval = -EINVAL; | 1114 | int retval = -EINVAL; |
1116 | 1115 | ||
1117 | /* | 1116 | /* |
1118 | * Converted the lock_cpu_hotplug to preempt_disable() | 1117 | * If we are already in context of hotplug thread, we dont need to |
1119 | * and preempt_enable(). This is a bit kludgy and relies on how cpu | 1118 | * acquire the hotplug lock. Otherwise acquire cpucontrol to prevent |
1120 | * hotplug works. All we need is a guarantee that cpu hotplug won't make | 1119 | * hotplug from removing this cpu that we are working on. |
1121 | * progress on any cpu. Once we do preempt_disable(), this would ensure | ||
1122 | * that hotplug threads don't get onto this cpu, thereby delaying | ||
1123 | * the cpu remove process. | ||
1124 | * | ||
1125 | * We removed the lock_cpu_hotplug since we need to call this function | ||
1126 | * via cpu hotplug callbacks, which result in locking the cpu hotplug | ||
1127 | * thread itself. Agree this is not very clean, cpufreq community | ||
1128 | * could improve this if required. - Ashok Raj <ashok.raj@intel.com> | ||
1129 | */ | 1120 | */ |
1130 | preempt_disable(); | 1121 | if (!current_in_cpu_hotplug()) |
1122 | lock_cpu_hotplug(); | ||
1123 | |||
1131 | dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, | 1124 | dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, |
1132 | target_freq, relation); | 1125 | target_freq, relation); |
1133 | if (cpu_online(policy->cpu) && cpufreq_driver->target) | 1126 | if (cpu_online(policy->cpu) && cpufreq_driver->target) |
1134 | retval = cpufreq_driver->target(policy, target_freq, relation); | 1127 | retval = cpufreq_driver->target(policy, target_freq, relation); |
1135 | preempt_enable(); | 1128 | |
1129 | if (!current_in_cpu_hotplug()) | ||
1130 | unlock_cpu_hotplug(); | ||
1131 | |||
1136 | return retval; | 1132 | return retval; |
1137 | } | 1133 | } |
1138 | EXPORT_SYMBOL_GPL(__cpufreq_driver_target); | 1134 | EXPORT_SYMBOL_GPL(__cpufreq_driver_target); |
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 1f7b2c097503..43c44530ef9d 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h | |||
@@ -42,6 +42,7 @@ struct notifier_block; | |||
42 | /* Need to know about CPUs going up/down? */ | 42 | /* Need to know about CPUs going up/down? */ |
43 | extern int register_cpu_notifier(struct notifier_block *nb); | 43 | extern int register_cpu_notifier(struct notifier_block *nb); |
44 | extern void unregister_cpu_notifier(struct notifier_block *nb); | 44 | extern void unregister_cpu_notifier(struct notifier_block *nb); |
45 | extern int current_in_cpu_hotplug(void); | ||
45 | 46 | ||
46 | int cpu_up(unsigned int cpu); | 47 | int cpu_up(unsigned int cpu); |
47 | 48 | ||
@@ -54,6 +55,10 @@ static inline int register_cpu_notifier(struct notifier_block *nb) | |||
54 | static inline void unregister_cpu_notifier(struct notifier_block *nb) | 55 | static inline void unregister_cpu_notifier(struct notifier_block *nb) |
55 | { | 56 | { |
56 | } | 57 | } |
58 | static inline int current_in_cpu_hotplug(void) | ||
59 | { | ||
60 | return 0; | ||
61 | } | ||
57 | 62 | ||
58 | #endif /* CONFIG_SMP */ | 63 | #endif /* CONFIG_SMP */ |
59 | extern struct sysdev_class cpu_sysdev_class; | 64 | extern struct sysdev_class cpu_sysdev_class; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 03b68a7b4b82..2bbf968b23d9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -909,6 +909,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) | |||
909 | #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ | 909 | #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ |
910 | #define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ | 910 | #define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ |
911 | #define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ | 911 | #define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ |
912 | #define PF_HOTPLUG_CPU 0x01000000 /* Currently performing CPU hotplug */ | ||
912 | 913 | ||
913 | /* | 914 | /* |
914 | * Only the _current_ task can read/write to tsk->flags, but other | 915 | * Only the _current_ task can read/write to tsk->flags, but other |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 3619e939182e..d61ba88f34e5 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -21,6 +21,24 @@ EXPORT_SYMBOL_GPL(cpucontrol); | |||
21 | 21 | ||
22 | static struct notifier_block *cpu_chain; | 22 | static struct notifier_block *cpu_chain; |
23 | 23 | ||
24 | /* | ||
25 | * Used to check by callers if they need to acquire the cpucontrol | ||
26 | * or not to protect a cpu from being removed. Its sometimes required to | ||
27 | * call these functions both for normal operations, and in response to | ||
28 | * a cpu being added/removed. If the context of the call is in the same | ||
29 | * thread context as a CPU hotplug thread, we dont need to take the lock | ||
30 | * since its already protected | ||
31 | * check drivers/cpufreq/cpufreq.c for its usage - Ashok Raj | ||
32 | */ | ||
33 | |||
34 | int current_in_cpu_hotplug(void) | ||
35 | { | ||
36 | return (current->flags & PF_HOTPLUG_CPU); | ||
37 | } | ||
38 | |||
39 | EXPORT_SYMBOL_GPL(current_in_cpu_hotplug); | ||
40 | |||
41 | |||
24 | /* Need to know about CPUs going up/down? */ | 42 | /* Need to know about CPUs going up/down? */ |
25 | int register_cpu_notifier(struct notifier_block *nb) | 43 | int register_cpu_notifier(struct notifier_block *nb) |
26 | { | 44 | { |
@@ -94,6 +112,13 @@ int cpu_down(unsigned int cpu) | |||
94 | goto out; | 112 | goto out; |
95 | } | 113 | } |
96 | 114 | ||
115 | /* | ||
116 | * Leave a trace in current->flags indicating we are already in | ||
117 | * process of performing CPU hotplug. Callers can check if cpucontrol | ||
118 | * is already acquired by current thread, and if so not cause | ||
119 | * a dead lock by not acquiring the lock | ||
120 | */ | ||
121 | current->flags |= PF_HOTPLUG_CPU; | ||
97 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, | 122 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, |
98 | (void *)(long)cpu); | 123 | (void *)(long)cpu); |
99 | if (err == NOTIFY_BAD) { | 124 | if (err == NOTIFY_BAD) { |
@@ -146,6 +171,7 @@ out_thread: | |||
146 | out_allowed: | 171 | out_allowed: |
147 | set_cpus_allowed(current, old_allowed); | 172 | set_cpus_allowed(current, old_allowed); |
148 | out: | 173 | out: |
174 | current->flags &= ~PF_HOTPLUG_CPU; | ||
149 | unlock_cpu_hotplug(); | 175 | unlock_cpu_hotplug(); |
150 | return err; | 176 | return err; |
151 | } | 177 | } |
@@ -163,6 +189,12 @@ int __devinit cpu_up(unsigned int cpu) | |||
163 | ret = -EINVAL; | 189 | ret = -EINVAL; |
164 | goto out; | 190 | goto out; |
165 | } | 191 | } |
192 | |||
193 | /* | ||
194 | * Leave a trace in current->flags indicating we are already in | ||
195 | * process of performing CPU hotplug. | ||
196 | */ | ||
197 | current->flags |= PF_HOTPLUG_CPU; | ||
166 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); | 198 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); |
167 | if (ret == NOTIFY_BAD) { | 199 | if (ret == NOTIFY_BAD) { |
168 | printk("%s: attempt to bring up CPU %u failed\n", | 200 | printk("%s: attempt to bring up CPU %u failed\n", |
@@ -185,6 +217,7 @@ out_notify: | |||
185 | if (ret != 0) | 217 | if (ret != 0) |
186 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); | 218 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); |
187 | out: | 219 | out: |
220 | current->flags &= ~PF_HOTPLUG_CPU; | ||
188 | up(&cpucontrol); | 221 | up(&cpucontrol); |
189 | return ret; | 222 | return ret; |
190 | } | 223 | } |