diff options
Diffstat (limited to 'include/linux/smp.h')
-rw-r--r-- | include/linux/smp.h | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/include/linux/smp.h b/include/linux/smp.h new file mode 100644 index 000000000..a80ab58ae --- /dev/null +++ b/include/linux/smp.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_SMP_H +#define __LINUX_SMP_H + +/* + * Generic SMP support + * Alan Cox. <alan@redhat.com> + */ + +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/cpumask.h> +#include <linux/init.h> +#include <linux/smp_types.h> + +typedef void (*smp_call_func_t)(void *info); +typedef bool (*smp_cond_func_t)(int cpu, void *info); + +/* + * structure shares (partial) layout with struct irq_work + */ +struct __call_single_data { + struct __call_single_node node; + smp_call_func_t func; + void *info; +}; + +#define CSD_INIT(_func, _info) \ + (struct __call_single_data){ .func = (_func), .info = (_info), } + +/* Use __aligned() to avoid to use 2 cache lines for 1 csd */ +typedef struct __call_single_data call_single_data_t + __aligned(sizeof(struct __call_single_data)); + +#define INIT_CSD(_csd, _func, _info) \ +do { \ + *(_csd) = CSD_INIT((_func), (_info)); \ +} while (0) + +/* + * Enqueue a llist_node on the call_single_queue; be very careful, read + * flush_smp_call_function_queue() in detail. + */ +extern void __smp_call_single_queue(int cpu, struct llist_node *node); + +/* total number of cpus in this system (may exceed NR_CPUS) */ +extern unsigned int total_cpus; + +int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, + int wait); + +void on_each_cpu_cond_mask(smp_cond_func_t cond_func, smp_call_func_t func, + void *info, bool wait, const struct cpumask *mask); + +int smp_call_function_single_async(int cpu, struct __call_single_data *csd); + +/* + * Cpus stopping functions in panic. All have default weak definitions. + * Architecture-dependent code may override them. + */ +void panic_smp_self_stop(void); +void nmi_panic_self_stop(struct pt_regs *regs); +void crash_smp_send_stop(void); + +/* + * Call a function on all processors + */ +static inline void on_each_cpu(smp_call_func_t func, void *info, int wait) +{ + on_each_cpu_cond_mask(NULL, func, info, wait, cpu_online_mask); +} + +/** + * on_each_cpu_mask(): Run a function on processors specified by + * cpumask, which may include the local processor. + * @mask: The set of cpus to run on (only runs on online subset). + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @wait: If true, wait (atomically) until function has completed + * on other CPUs. + * + * If @wait is true, then returns once @func has returned. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. The + * exception is that it may be used during early boot while + * early_boot_irqs_disabled is set. + */ +static inline void on_each_cpu_mask(const struct cpumask *mask, + smp_call_func_t func, void *info, bool wait) +{ + on_each_cpu_cond_mask(NULL, func, info, wait, mask); +} + +/* + * Call a function on each processor for which the supplied function + * cond_func returns a positive value. This may include the local + * processor. May be used during early boot while early_boot_irqs_disabled is + * set. Use local_irq_save/restore() instead of local_irq_disable/enable(). + */ +static inline void on_each_cpu_cond(smp_cond_func_t cond_func, + smp_call_func_t func, void *info, bool wait) +{ + on_each_cpu_cond_mask(cond_func, func, info, wait, cpu_online_mask); +} + +#ifdef CONFIG_SMP + +#include <linux/preempt.h> +#include <linux/compiler.h> +#include <linux/thread_info.h> +#include <asm/smp.h> + +/* + * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc. + * (defined in asm header): + */ + +/* + * stops all CPUs but the current one: + */ +extern void smp_send_stop(void); + +/* + * sends a 'reschedule' event to another CPU: + */ +extern void smp_send_reschedule(int cpu); + + +/* + * Prepare machine for booting other CPUs. + */ +extern void smp_prepare_cpus(unsigned int max_cpus); + +/* + * Bring a CPU up + */ +extern int __cpu_up(unsigned int cpunum, struct task_struct *tidle); + +/* + * Final polishing of CPUs + */ +extern void smp_cpus_done(unsigned int max_cpus); + +/* + * Call a function on all other processors + */ +void smp_call_function(smp_call_func_t func, void *info, int wait); +void smp_call_function_many(const struct cpumask *mask, + smp_call_func_t func, void *info, bool wait); + +int smp_call_function_any(const struct cpumask *mask, + smp_call_func_t func, void *info, int wait); + +void kick_all_cpus_sync(void); +void wake_up_all_idle_cpus(void); + +/* + * Generic and arch helpers + */ +void __init call_function_init(void); +void generic_smp_call_function_single_interrupt(void); +#define generic_smp_call_function_interrupt \ + generic_smp_call_function_single_interrupt + +/* + * Mark the boot cpu "online" so that it can call console drivers in + * printk() and can access its per-cpu storage. + */ +void smp_prepare_boot_cpu(void); + +extern unsigned int setup_max_cpus; +extern void __init setup_nr_cpu_ids(void); +extern void __init smp_init(void); + +extern int __boot_cpu_id; + +static inline int get_boot_cpu_id(void) +{ + return __boot_cpu_id; +} + +#else /* !SMP */ + +static inline void smp_send_stop(void) { } + +/* + * These macros fold the SMP functionality into a single CPU system + */ +#define raw_smp_processor_id() 0 +static inline void up_smp_call_function(smp_call_func_t func, void *info) +{ +} +#define smp_call_function(func, info, wait) \ + (up_smp_call_function(func, info)) + +static inline void smp_send_reschedule(int cpu) { } +#define smp_prepare_boot_cpu() do {} while (0) +#define smp_call_function_many(mask, func, info, wait) \ + (up_smp_call_function(func, info)) +static inline void call_function_init(void) { } + +static inline int +smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, + void *info, int wait) +{ + return smp_call_function_single(0, func, info, wait); +} + +static inline void kick_all_cpus_sync(void) { } +static inline void wake_up_all_idle_cpus(void) { } + +#ifdef CONFIG_UP_LATE_INIT +extern void __init up_late_init(void); +static inline void smp_init(void) { up_late_init(); } +#else +static inline void smp_init(void) { } +#endif + +static inline int get_boot_cpu_id(void) +{ + return 0; +} + +#endif /* !SMP */ + +/** + * raw_processor_id() - get the current (unstable) CPU id + * + * For then you know what you are doing and need an unstable + * CPU id. + */ + +/** + * smp_processor_id() - get the current (stable) CPU id + * + * This is the normal accessor to the CPU id and should be used + * whenever possible. + * + * The CPU id is stable when: + * + * - IRQs are disabled; + * - preemption is disabled; + * - the task is CPU affine. + * + * When CONFIG_DEBUG_PREEMPT; we verify these assumption and WARN + * when smp_processor_id() is used when the CPU id is not stable. + */ + +/* + * Allow the architecture to differentiate between a stable and unstable read. + * For example, x86 uses an IRQ-safe asm-volatile read for the unstable but a + * regular asm read for the stable. + */ +#ifndef __smp_processor_id +#define __smp_processor_id(x) raw_smp_processor_id(x) +#endif + +#ifdef CONFIG_DEBUG_PREEMPT + extern unsigned int debug_smp_processor_id(void); +# define smp_processor_id() debug_smp_processor_id() +#else +# define smp_processor_id() __smp_processor_id() +#endif + +#define get_cpu() ({ preempt_disable(); __smp_processor_id(); }) +#define put_cpu() preempt_enable() + +/* + * Callback to arch code if there's nosmp or maxcpus=0 on the + * boot command line: + */ +extern void arch_disable_smp_support(void); + +extern void arch_thaw_secondary_cpus_begin(void); +extern void arch_thaw_secondary_cpus_end(void); + +void smp_setup_processor_id(void); + +int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, + bool phys); + +/* SMP core functions */ +int smpcfd_prepare_cpu(unsigned int cpu); +int smpcfd_dead_cpu(unsigned int cpu); +int smpcfd_dying_cpu(unsigned int cpu); + +#endif /* __LINUX_SMP_H */ |