1caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
208e875c1SCatalin Marinas /*
308e875c1SCatalin Marinas * Copyright (C) 2012 ARM Ltd.
408e875c1SCatalin Marinas */
508e875c1SCatalin Marinas #ifndef __ASM_SMP_H
608e875c1SCatalin Marinas #define __ASM_SMP_H
708e875c1SCatalin Marinas
81236cd2bSShaokun Zhang #include <linux/const.h>
91236cd2bSShaokun Zhang
10bb905274SSuzuki K Poulose /* Values for secondary_data.status */
1166f16a24SWill Deacon #define CPU_STUCK_REASON_SHIFT (8)
121236cd2bSShaokun Zhang #define CPU_BOOT_STATUS_MASK ((UL(1) << CPU_STUCK_REASON_SHIFT) - 1)
13bb905274SSuzuki K Poulose
14bb905274SSuzuki K Poulose #define CPU_MMU_OFF (-1)
15bb905274SSuzuki K Poulose #define CPU_BOOT_SUCCESS (0)
16bb905274SSuzuki K Poulose /* The cpu invoked ops->cpu_die, synchronise it with cpu_kill */
17bb905274SSuzuki K Poulose #define CPU_KILL_ME (1)
18bb905274SSuzuki K Poulose /* The cpu couldn't die gracefully and is looping in the kernel */
19bb905274SSuzuki K Poulose #define CPU_STUCK_IN_KERNEL (2)
20bb905274SSuzuki K Poulose /* Fatal system error detected by secondary CPU, crash the system */
21bb905274SSuzuki K Poulose #define CPU_PANIC_KERNEL (3)
22bb905274SSuzuki K Poulose
231236cd2bSShaokun Zhang #define CPU_STUCK_REASON_52_BIT_VA (UL(1) << CPU_STUCK_REASON_SHIFT)
241236cd2bSShaokun Zhang #define CPU_STUCK_REASON_NO_GRAN (UL(2) << CPU_STUCK_REASON_SHIFT)
2566f16a24SWill Deacon
26bb905274SSuzuki K Poulose #ifndef __ASSEMBLY__
27bb905274SSuzuki K Poulose
2857c82954SMark Rutland #include <asm/percpu.h>
2957c82954SMark Rutland
3008e875c1SCatalin Marinas #include <linux/threads.h>
3108e875c1SCatalin Marinas #include <linux/cpumask.h>
3208e875c1SCatalin Marinas #include <linux/thread_info.h>
3308e875c1SCatalin Marinas
3457c82954SMark Rutland DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
3557c82954SMark Rutland
3657c82954SMark Rutland /*
3757c82954SMark Rutland * We don't use this_cpu_read(cpu_number) as that has implicit writes to
3857c82954SMark Rutland * preempt_count, and associated (compiler) barriers, that we'd like to avoid
3957c82954SMark Rutland * the expense of. If we're preemptible, the value can be stale at use anyway.
4034a6980cSRobin Murphy * And we can't use this_cpu_ptr() either, as that winds up recursing back
4134a6980cSRobin Murphy * here under CONFIG_DEBUG_PREEMPT=y.
4257c82954SMark Rutland */
4334a6980cSRobin Murphy #define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
4408e875c1SCatalin Marinas
45262afe92SFlorian Fainelli /*
46262afe92SFlorian Fainelli * Logical CPU mapping.
47262afe92SFlorian Fainelli */
48262afe92SFlorian Fainelli extern u64 __cpu_logical_map[NR_CPUS];
49c1f45f4eSDavid Brazdil extern u64 cpu_logical_map(unsigned int cpu);
50eaecca9eSKefeng Wang
set_cpu_logical_map(unsigned int cpu,u64 hwid)51c1f45f4eSDavid Brazdil static inline void set_cpu_logical_map(unsigned int cpu, u64 hwid)
52eaecca9eSKefeng Wang {
53eaecca9eSKefeng Wang __cpu_logical_map[cpu] = hwid;
54eaecca9eSKefeng Wang }
55262afe92SFlorian Fainelli
5608e875c1SCatalin Marinas struct seq_file;
5708e875c1SCatalin Marinas
5808e875c1SCatalin Marinas /*
59fccb9a81SHanjun Guo * Discover the set of possible CPUs and determine their
60fccb9a81SHanjun Guo * SMP operations.
6108e875c1SCatalin Marinas */
620f078336SLorenzo Pieralisi extern void smp_init_cpus(void);
6308e875c1SCatalin Marinas
6408e875c1SCatalin Marinas /*
65d3afc7f1SMarc Zyngier * Register IPI interrupts with the arch SMP code
66d3afc7f1SMarc Zyngier */
67d3afc7f1SMarc Zyngier extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
68d3afc7f1SMarc Zyngier
69d3afc7f1SMarc Zyngier /*
7008e875c1SCatalin Marinas * Called from the secondary holding pen, this is the secondary CPU entry point.
7108e875c1SCatalin Marinas */
7208e875c1SCatalin Marinas asmlinkage void secondary_start_kernel(void);
7308e875c1SCatalin Marinas
7408e875c1SCatalin Marinas /*
7508e875c1SCatalin Marinas * Initial data for bringing up a secondary CPU.
76bb905274SSuzuki K Poulose * @status - Result passed back from the secondary CPU to
77bb905274SSuzuki K Poulose * indicate failure.
7808e875c1SCatalin Marinas */
7908e875c1SCatalin Marinas struct secondary_data {
80c02433ddSMark Rutland struct task_struct *task;
81bb905274SSuzuki K Poulose long status;
8208e875c1SCatalin Marinas };
83bb905274SSuzuki K Poulose
8408e875c1SCatalin Marinas extern struct secondary_data secondary_data;
85bb905274SSuzuki K Poulose extern long __early_cpu_boot_status;
86652af899SMark Rutland extern void secondary_entry(void);
8708e875c1SCatalin Marinas
8808e875c1SCatalin Marinas extern void arch_send_call_function_single_ipi(int cpu);
8908e875c1SCatalin Marinas extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
9008e875c1SCatalin Marinas
915e89c55eSLorenzo Pieralisi #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
925e89c55eSLorenzo Pieralisi extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
935e89c55eSLorenzo Pieralisi #else
arch_send_wakeup_ipi_mask(const struct cpumask * mask)945e89c55eSLorenzo Pieralisi static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
955e89c55eSLorenzo Pieralisi {
965e89c55eSLorenzo Pieralisi BUILD_BUG();
975e89c55eSLorenzo Pieralisi }
985e89c55eSLorenzo Pieralisi #endif
995e89c55eSLorenzo Pieralisi
1009327e2c6SMark Rutland extern int __cpu_disable(void);
1019327e2c6SMark Rutland
__cpu_die(unsigned int cpu)1029327e2c6SMark Rutland static inline void __cpu_die(unsigned int cpu) { }
1039bdc61efSJosh Poimboeuf extern void __noreturn cpu_die(void);
104*5ab6876cSJosh Poimboeuf extern void __noreturn cpu_die_early(void);
1059327e2c6SMark Rutland
cpu_park_loop(void)106*5ab6876cSJosh Poimboeuf static inline void __noreturn cpu_park_loop(void)
107c4bc34d2SSuzuki K Poulose {
108c4bc34d2SSuzuki K Poulose for (;;) {
109c4bc34d2SSuzuki K Poulose wfe();
110c4bc34d2SSuzuki K Poulose wfi();
111c4bc34d2SSuzuki K Poulose }
112c4bc34d2SSuzuki K Poulose }
113c4bc34d2SSuzuki K Poulose
update_cpu_boot_status(int val)114bb905274SSuzuki K Poulose static inline void update_cpu_boot_status(int val)
115bb905274SSuzuki K Poulose {
116bb905274SSuzuki K Poulose WRITE_ONCE(secondary_data.status, val);
117bb905274SSuzuki K Poulose /* Ensure the visibility of the status update */
118bb905274SSuzuki K Poulose dsb(ishst);
119bb905274SSuzuki K Poulose }
120bb905274SSuzuki K Poulose
12117eebd1aSSuzuki K Poulose /*
12217eebd1aSSuzuki K Poulose * The calling secondary CPU has detected serious configuration mismatch,
12317eebd1aSSuzuki K Poulose * which calls for a kernel panic. Update the boot status and park the calling
12417eebd1aSSuzuki K Poulose * CPU.
12517eebd1aSSuzuki K Poulose */
cpu_panic_kernel(void)126*5ab6876cSJosh Poimboeuf static inline void __noreturn cpu_panic_kernel(void)
12717eebd1aSSuzuki K Poulose {
12817eebd1aSSuzuki K Poulose update_cpu_boot_status(CPU_PANIC_KERNEL);
12917eebd1aSSuzuki K Poulose cpu_park_loop();
13017eebd1aSSuzuki K Poulose }
13117eebd1aSSuzuki K Poulose
1325c492c3fSJames Morse /*
1335c492c3fSJames Morse * If a secondary CPU enters the kernel but fails to come online,
1345c492c3fSJames Morse * (e.g. due to mismatched features), and cannot exit the kernel,
1355c492c3fSJames Morse * we increment cpus_stuck_in_kernel and leave the CPU in a
1365c492c3fSJames Morse * quiesecent loop within the kernel text. The memory containing
1375c492c3fSJames Morse * this loop must not be re-used for anything else as the 'stuck'
1385c492c3fSJames Morse * core is executing it.
1395c492c3fSJames Morse *
1405c492c3fSJames Morse * This function is used to inhibit features like kexec and hibernate.
1415c492c3fSJames Morse */
1425c492c3fSJames Morse bool cpus_are_stuck_in_kernel(void);
1435c492c3fSJames Morse
144a88ce63bSHoeun Ryu extern void crash_smp_send_stop(void);
14578fd584cSAKASHI Takahiro extern bool smp_crash_stop_failed(void);
14678fd584cSAKASHI Takahiro
147bb905274SSuzuki K Poulose #endif /* ifndef __ASSEMBLY__ */
148bb905274SSuzuki K Poulose
14908e875c1SCatalin Marinas #endif /* ifndef __ASM_SMP_H */
150