162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#ifndef __ASM_SMP_H
662306a36Sopenharmony_ci#define __ASM_SMP_H
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/const.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* Values for secondary_data.status */
1162306a36Sopenharmony_ci#define CPU_STUCK_REASON_SHIFT		(8)
1262306a36Sopenharmony_ci#define CPU_BOOT_STATUS_MASK		((UL(1) << CPU_STUCK_REASON_SHIFT) - 1)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define CPU_MMU_OFF			(-1)
1562306a36Sopenharmony_ci#define CPU_BOOT_SUCCESS		(0)
1662306a36Sopenharmony_ci/* The cpu invoked ops->cpu_die, synchronise it with cpu_kill */
1762306a36Sopenharmony_ci#define CPU_KILL_ME			(1)
1862306a36Sopenharmony_ci/* The cpu couldn't die gracefully and is looping in the kernel */
1962306a36Sopenharmony_ci#define CPU_STUCK_IN_KERNEL		(2)
2062306a36Sopenharmony_ci/* Fatal system error detected by secondary CPU, crash the system */
2162306a36Sopenharmony_ci#define CPU_PANIC_KERNEL		(3)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define CPU_STUCK_REASON_52_BIT_VA	(UL(1) << CPU_STUCK_REASON_SHIFT)
2462306a36Sopenharmony_ci#define CPU_STUCK_REASON_NO_GRAN	(UL(2) << CPU_STUCK_REASON_SHIFT)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#ifndef __ASSEMBLY__
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <asm/percpu.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/threads.h>
3162306a36Sopenharmony_ci#include <linux/cpumask.h>
3262306a36Sopenharmony_ci#include <linux/thread_info.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciDECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * We don't use this_cpu_read(cpu_number) as that has implicit writes to
3862306a36Sopenharmony_ci * preempt_count, and associated (compiler) barriers, that we'd like to avoid
3962306a36Sopenharmony_ci * the expense of. If we're preemptible, the value can be stale at use anyway.
4062306a36Sopenharmony_ci * And we can't use this_cpu_ptr() either, as that winds up recursing back
4162306a36Sopenharmony_ci * here under CONFIG_DEBUG_PREEMPT=y.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/*
4662306a36Sopenharmony_ci * Logical CPU mapping.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ciextern u64 __cpu_logical_map[NR_CPUS];
4962306a36Sopenharmony_ciextern u64 cpu_logical_map(unsigned int cpu);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic inline void set_cpu_logical_map(unsigned int cpu, u64 hwid)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	__cpu_logical_map[cpu] = hwid;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct seq_file;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/*
5962306a36Sopenharmony_ci * Discover the set of possible CPUs and determine their
6062306a36Sopenharmony_ci * SMP operations.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ciextern void smp_init_cpus(void);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * Register IPI interrupts with the arch SMP code
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ciextern void set_smp_ipi_range(int ipi_base, int nr_ipi);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * Called from the secondary holding pen, this is the secondary CPU entry point.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_ciasmlinkage void secondary_start_kernel(void);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * Initial data for bringing up a secondary CPU.
7662306a36Sopenharmony_ci * @status - Result passed back from the secondary CPU to
7762306a36Sopenharmony_ci *           indicate failure.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_cistruct secondary_data {
8062306a36Sopenharmony_ci	struct task_struct *task;
8162306a36Sopenharmony_ci	long status;
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ciextern struct secondary_data secondary_data;
8562306a36Sopenharmony_ciextern long __early_cpu_boot_status;
8662306a36Sopenharmony_ciextern void secondary_entry(void);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciextern void arch_send_call_function_single_ipi(int cpu);
8962306a36Sopenharmony_ciextern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
9262306a36Sopenharmony_ciextern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
9362306a36Sopenharmony_ci#else
9462306a36Sopenharmony_cistatic inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	BUILD_BUG();
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci#endif
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciextern int __cpu_disable(void);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline void __cpu_die(unsigned int cpu) { }
10362306a36Sopenharmony_ciextern void __noreturn cpu_die(void);
10462306a36Sopenharmony_ciextern void __noreturn cpu_die_early(void);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic inline void __noreturn cpu_park_loop(void)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	for (;;) {
10962306a36Sopenharmony_ci		wfe();
11062306a36Sopenharmony_ci		wfi();
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline void update_cpu_boot_status(int val)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	WRITE_ONCE(secondary_data.status, val);
11762306a36Sopenharmony_ci	/* Ensure the visibility of the status update */
11862306a36Sopenharmony_ci	dsb(ishst);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * The calling secondary CPU has detected serious configuration mismatch,
12362306a36Sopenharmony_ci * which calls for a kernel panic. Update the boot status and park the calling
12462306a36Sopenharmony_ci * CPU.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistatic inline void __noreturn cpu_panic_kernel(void)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	update_cpu_boot_status(CPU_PANIC_KERNEL);
12962306a36Sopenharmony_ci	cpu_park_loop();
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * If a secondary CPU enters the kernel but fails to come online,
13462306a36Sopenharmony_ci * (e.g. due to mismatched features), and cannot exit the kernel,
13562306a36Sopenharmony_ci * we increment cpus_stuck_in_kernel and leave the CPU in a
13662306a36Sopenharmony_ci * quiesecent loop within the kernel text. The memory containing
13762306a36Sopenharmony_ci * this loop must not be re-used for anything else as the 'stuck'
13862306a36Sopenharmony_ci * core is executing it.
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * This function is used to inhibit features like kexec and hibernate.
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cibool cpus_are_stuck_in_kernel(void);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciextern void crash_smp_send_stop(void);
14562306a36Sopenharmony_ciextern bool smp_crash_stop_failed(void);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#endif /* ifndef __ASSEMBLY__ */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#endif /* ifndef __ASM_SMP_H */
150