diff options
Diffstat (limited to 'include/linux/stop_machine.h')
| -rw-r--r-- | include/linux/stop_machine.h | 122 | 
1 files changed, 95 insertions, 27 deletions
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index baba3a23a81..6b524a0d02e 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h @@ -1,13 +1,101 @@  #ifndef _LINUX_STOP_MACHINE  #define _LINUX_STOP_MACHINE -/* "Bogolock": stop the entire machine, disable interrupts.  This is a -   very heavy lock, which is equivalent to grabbing every spinlock -   (and more).  So the "read" side to such a lock is anything which -   disables preeempt. */ +  #include <linux/cpu.h>  #include <linux/cpumask.h> +#include <linux/list.h>  #include <asm/system.h> +/* + * stop_cpu[s]() is simplistic per-cpu maximum priority cpu + * monopolization mechanism.  The caller can specify a non-sleeping + * function to be executed on a single or multiple cpus preempting all + * other processes and monopolizing those cpus until it finishes. + * + * Resources for this mechanism are preallocated when a cpu is brought + * up and requests are guaranteed to be served as long as the target + * cpus are online. + */ +typedef int (*cpu_stop_fn_t)(void *arg); + +#ifdef CONFIG_SMP + +struct cpu_stop_work { +	struct list_head	list;		/* cpu_stopper->works */ +	cpu_stop_fn_t		fn; +	void			*arg; +	struct cpu_stop_done	*done; +}; + +int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg); +void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, +			 struct cpu_stop_work *work_buf); +int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg); +int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg); + +#else	/* CONFIG_SMP */ + +#include <linux/workqueue.h> + +struct cpu_stop_work { +	struct work_struct	work; +	cpu_stop_fn_t		fn; +	void			*arg; +}; + +static inline int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg) +{ +	int ret = -ENOENT; +	preempt_disable(); +	if (cpu == smp_processor_id()) +		ret = fn(arg); +	preempt_enable(); +	return ret; +} + +static void stop_one_cpu_nowait_workfn(struct work_struct *work) +{ +	struct cpu_stop_work *stwork = +		container_of(work, struct cpu_stop_work, work); +	preempt_disable(); +	stwork->fn(stwork->arg); +	preempt_enable(); +} + +static inline void stop_one_cpu_nowait(unsigned int cpu, +				       cpu_stop_fn_t fn, void *arg, +				       struct cpu_stop_work *work_buf) +{ +	if (cpu == smp_processor_id()) { +		INIT_WORK(&work_buf->work, stop_one_cpu_nowait_workfn); +		work_buf->fn = fn; +		work_buf->arg = arg; +		schedule_work(&work_buf->work); +	} +} + +static inline int stop_cpus(const struct cpumask *cpumask, +			    cpu_stop_fn_t fn, void *arg) +{ +	if (cpumask_test_cpu(raw_smp_processor_id(), cpumask)) +		return stop_one_cpu(raw_smp_processor_id(), fn, arg); +	return -ENOENT; +} + +static inline int try_stop_cpus(const struct cpumask *cpumask, +				cpu_stop_fn_t fn, void *arg) +{ +	return stop_cpus(cpumask, fn, arg); +} + +#endif	/* CONFIG_SMP */ + +/* + * stop_machine "Bogolock": stop the entire machine, disable + * interrupts.  This is a very heavy lock, which is equivalent to + * grabbing every spinlock (and more).  So the "read" side to such a + * lock is anything which disables preeempt. + */  #if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)  /** @@ -36,24 +124,7 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);   */  int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); -/** - * stop_machine_create: create all stop_machine threads - * - * Description: This causes all stop_machine threads to be created before - * stop_machine actually gets called. This can be used by subsystems that - * need a non failing stop_machine infrastructure. - */ -int stop_machine_create(void); - -/** - * stop_machine_destroy: destroy all stop_machine threads - * - * Description: This causes all stop_machine threads which were created with - * stop_machine_create to be destroyed again. - */ -void stop_machine_destroy(void); - -#else +#else	 /* CONFIG_STOP_MACHINE && CONFIG_SMP */  static inline int stop_machine(int (*fn)(void *), void *data,  			       const struct cpumask *cpus) @@ -65,8 +136,5 @@ static inline int stop_machine(int (*fn)(void *), void *data,  	return ret;  } -static inline int stop_machine_create(void) { return 0; } -static inline void stop_machine_destroy(void) { } - -#endif /* CONFIG_SMP */ -#endif /* _LINUX_STOP_MACHINE */ +#endif	/* CONFIG_STOP_MACHINE && CONFIG_SMP */ +#endif	/* _LINUX_STOP_MACHINE */  |