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