X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=kernel%2Fcpu.c;h=d61ba88f34e57b90edae90342ed1db59ebfbb59c;hb=d11ea48aab3b57cc931cc7120603e1c2ffb04302;hp=53d8263ae12ebc00483a3ad999177799003467e2;hpb=aef7b83c92dd0b7e994805440655d1d64147287b;p=linux-2.6-omap-h63xx.git diff --git a/kernel/cpu.c b/kernel/cpu.c index 53d8263ae12..f230f9ae01c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -13,35 +13,69 @@ #include #include #include -#include +#include /* This protects CPUs going up and down... */ -DECLARE_MUTEX(cpucontrol); +static DEFINE_MUTEX(cpu_add_remove_lock); +static DEFINE_MUTEX(cpu_bitmask_lock); -static struct notifier_block *cpu_chain; +static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain); -/* Need to know about CPUs going up/down? */ -int register_cpu_notifier(struct notifier_block *nb) +#ifdef CONFIG_HOTPLUG_CPU + +/* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */ +static struct task_struct *recursive; +static int recursive_depth; + +void lock_cpu_hotplug(void) { - int ret; + struct task_struct *tsk = current; + + if (tsk == recursive) { + static int warnings = 10; + if (warnings) { + printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n"); + WARN_ON(1); + warnings--; + } + recursive_depth++; + return; + } + mutex_lock(&cpu_bitmask_lock); + recursive = tsk; +} +EXPORT_SYMBOL_GPL(lock_cpu_hotplug); - if ((ret = down_interruptible(&cpucontrol)) != 0) - return ret; - ret = notifier_chain_register(&cpu_chain, nb); - up(&cpucontrol); - return ret; +void unlock_cpu_hotplug(void) +{ + WARN_ON(recursive != current); + if (recursive_depth) { + recursive_depth--; + return; + } + mutex_unlock(&cpu_bitmask_lock); + recursive = NULL; } +EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); + +#endif /* CONFIG_HOTPLUG_CPU */ + +/* Need to know about CPUs going up/down? */ +int __cpuinit register_cpu_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&cpu_chain, nb); +} + +#ifdef CONFIG_HOTPLUG_CPU + EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - down(&cpucontrol); - notifier_chain_unregister(&cpu_chain, nb); - up(&cpucontrol); + blocking_notifier_chain_unregister(&cpu_chain, nb); } EXPORT_SYMBOL(unregister_cpu_notifier); -#ifdef CONFIG_HOTPLUG_CPU static inline void check_for_tasks(int cpu) { struct task_struct *p; @@ -80,9 +114,7 @@ int cpu_down(unsigned int cpu) struct task_struct *p; cpumask_t old_allowed, tmp; - if ((err = lock_cpu_hotplug_interruptible()) != 0) - return err; - + mutex_lock(&cpu_add_remove_lock); if (num_online_cpus() == 1) { err = -EBUSY; goto out; @@ -93,7 +125,7 @@ int cpu_down(unsigned int cpu) goto out; } - err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, + err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, (void *)(long)cpu); if (err == NOTIFY_BAD) { printk("%s: attempt to take down CPU %u failed\n", @@ -108,10 +140,13 @@ int cpu_down(unsigned int cpu) cpu_clear(cpu, tmp); set_cpus_allowed(current, tmp); + mutex_lock(&cpu_bitmask_lock); p = __stop_machine_run(take_cpu_down, NULL, cpu); + mutex_unlock(&cpu_bitmask_lock); + if (IS_ERR(p)) { /* CPU didn't die: tell everyone. Can't complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, + if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, (void *)(long)cpu) == NOTIFY_BAD) BUG(); @@ -134,8 +169,8 @@ int cpu_down(unsigned int cpu) put_cpu(); /* CPU is completely dead: tell everyone. Too late to complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) - == NOTIFY_BAD) + if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, + (void *)(long)cpu) == NOTIFY_BAD) BUG(); check_for_tasks(cpu); @@ -145,7 +180,7 @@ out_thread: out_allowed: set_cpus_allowed(current, old_allowed); out: - unlock_cpu_hotplug(); + mutex_unlock(&cpu_add_remove_lock); return err; } #endif /*CONFIG_HOTPLUG_CPU*/ @@ -155,14 +190,13 @@ int __devinit cpu_up(unsigned int cpu) int ret; void *hcpu = (void *)(long)cpu; - if ((ret = down_interruptible(&cpucontrol)) != 0) - return ret; - + mutex_lock(&cpu_add_remove_lock); if (cpu_online(cpu) || !cpu_present(cpu)) { ret = -EINVAL; goto out; } - ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); + + ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); if (ret == NOTIFY_BAD) { printk("%s: attempt to bring up CPU %u failed\n", __FUNCTION__, cpu); @@ -171,19 +205,21 @@ int __devinit cpu_up(unsigned int cpu) } /* Arch-specific enabling code. */ + mutex_lock(&cpu_bitmask_lock); ret = __cpu_up(cpu); + mutex_unlock(&cpu_bitmask_lock); if (ret != 0) goto out_notify; - if (!cpu_online(cpu)) - BUG(); + BUG_ON(!cpu_online(cpu)); /* Now call notifier in preparation. */ - notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); + blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); out_notify: if (ret != 0) - notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); + blocking_notifier_call_chain(&cpu_chain, + CPU_UP_CANCELED, hcpu); out: - up(&cpucontrol); + mutex_unlock(&cpu_add_remove_lock); return ret; }