108e875c1SCatalin Marinas /* 208e875c1SCatalin Marinas * SMP initialisation and IPI support 308e875c1SCatalin Marinas * Based on arch/arm/kernel/smp.c 408e875c1SCatalin Marinas * 508e875c1SCatalin Marinas * Copyright (C) 2012 ARM Ltd. 608e875c1SCatalin Marinas * 708e875c1SCatalin Marinas * This program is free software; you can redistribute it and/or modify 808e875c1SCatalin Marinas * it under the terms of the GNU General Public License version 2 as 908e875c1SCatalin Marinas * published by the Free Software Foundation. 1008e875c1SCatalin Marinas * 1108e875c1SCatalin Marinas * This program is distributed in the hope that it will be useful, 1208e875c1SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 1308e875c1SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1408e875c1SCatalin Marinas * GNU General Public License for more details. 1508e875c1SCatalin Marinas * 1608e875c1SCatalin Marinas * You should have received a copy of the GNU General Public License 1708e875c1SCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 1808e875c1SCatalin Marinas */ 1908e875c1SCatalin Marinas 200f078336SLorenzo Pieralisi #include <linux/acpi.h> 2108e875c1SCatalin Marinas #include <linux/delay.h> 2208e875c1SCatalin Marinas #include <linux/init.h> 2308e875c1SCatalin Marinas #include <linux/spinlock.h> 2408e875c1SCatalin Marinas #include <linux/sched.h> 25ef8bd77fSIngo Molnar #include <linux/sched/hotplug.h> 26*68db0cf1SIngo Molnar #include <linux/sched/task_stack.h> 2708e875c1SCatalin Marinas #include <linux/interrupt.h> 2808e875c1SCatalin Marinas #include <linux/cache.h> 2908e875c1SCatalin Marinas #include <linux/profile.h> 3008e875c1SCatalin Marinas #include <linux/errno.h> 3108e875c1SCatalin Marinas #include <linux/mm.h> 3208e875c1SCatalin Marinas #include <linux/err.h> 3308e875c1SCatalin Marinas #include <linux/cpu.h> 3408e875c1SCatalin Marinas #include <linux/smp.h> 3508e875c1SCatalin Marinas #include <linux/seq_file.h> 3608e875c1SCatalin Marinas #include <linux/irq.h> 3708e875c1SCatalin Marinas #include <linux/percpu.h> 3808e875c1SCatalin Marinas #include <linux/clockchips.h> 3908e875c1SCatalin Marinas #include <linux/completion.h> 4008e875c1SCatalin Marinas #include <linux/of.h> 41eb631bb5SLarry Bassel #include <linux/irq_work.h> 4208e875c1SCatalin Marinas 43e039ee4eSAndre Przywara #include <asm/alternative.h> 4408e875c1SCatalin Marinas #include <asm/atomic.h> 4508e875c1SCatalin Marinas #include <asm/cacheflush.h> 46df857416SMark Rutland #include <asm/cpu.h> 4708e875c1SCatalin Marinas #include <asm/cputype.h> 48cd1aebf5SMark Rutland #include <asm/cpu_ops.h> 4908e875c1SCatalin Marinas #include <asm/mmu_context.h> 501a2db300SGanapatrao Kulkarni #include <asm/numa.h> 5108e875c1SCatalin Marinas #include <asm/pgtable.h> 5208e875c1SCatalin Marinas #include <asm/pgalloc.h> 5308e875c1SCatalin Marinas #include <asm/processor.h> 544c7aa002SJavi Merino #include <asm/smp_plat.h> 5508e875c1SCatalin Marinas #include <asm/sections.h> 5608e875c1SCatalin Marinas #include <asm/tlbflush.h> 5708e875c1SCatalin Marinas #include <asm/ptrace.h> 58377bcff9SJonas Rabenstein #include <asm/virt.h> 5908e875c1SCatalin Marinas 6045ed695aSNicolas Pitre #define CREATE_TRACE_POINTS 6145ed695aSNicolas Pitre #include <trace/events/ipi.h> 6245ed695aSNicolas Pitre 6357c82954SMark Rutland DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); 6457c82954SMark Rutland EXPORT_PER_CPU_SYMBOL(cpu_number); 6557c82954SMark Rutland 6608e875c1SCatalin Marinas /* 6708e875c1SCatalin Marinas * as from 2.5, kernels no longer have an init_tasks structure 6808e875c1SCatalin Marinas * so we need some other way of telling a new secondary core 6908e875c1SCatalin Marinas * where to place its SVC stack 7008e875c1SCatalin Marinas */ 7108e875c1SCatalin Marinas struct secondary_data secondary_data; 72bb905274SSuzuki K Poulose /* Number of CPUs which aren't online, but looping in kernel text. */ 73bb905274SSuzuki K Poulose int cpus_stuck_in_kernel; 7408e875c1SCatalin Marinas 7508e875c1SCatalin Marinas enum ipi_msg_type { 7608e875c1SCatalin Marinas IPI_RESCHEDULE, 7708e875c1SCatalin Marinas IPI_CALL_FUNC, 7808e875c1SCatalin Marinas IPI_CPU_STOP, 791f85008eSLorenzo Pieralisi IPI_TIMER, 80eb631bb5SLarry Bassel IPI_IRQ_WORK, 815e89c55eSLorenzo Pieralisi IPI_WAKEUP 8208e875c1SCatalin Marinas }; 8308e875c1SCatalin Marinas 84ac1ad20fSSuzuki K Poulose #ifdef CONFIG_ARM64_VHE 85ac1ad20fSSuzuki K Poulose 86ac1ad20fSSuzuki K Poulose /* Whether the boot CPU is running in HYP mode or not*/ 87ac1ad20fSSuzuki K Poulose static bool boot_cpu_hyp_mode; 88ac1ad20fSSuzuki K Poulose 89ac1ad20fSSuzuki K Poulose static inline void save_boot_cpu_run_el(void) 90ac1ad20fSSuzuki K Poulose { 91ac1ad20fSSuzuki K Poulose boot_cpu_hyp_mode = is_kernel_in_hyp_mode(); 92ac1ad20fSSuzuki K Poulose } 93ac1ad20fSSuzuki K Poulose 94ac1ad20fSSuzuki K Poulose static inline bool is_boot_cpu_in_hyp_mode(void) 95ac1ad20fSSuzuki K Poulose { 96ac1ad20fSSuzuki K Poulose return boot_cpu_hyp_mode; 97ac1ad20fSSuzuki K Poulose } 98ac1ad20fSSuzuki K Poulose 99ac1ad20fSSuzuki K Poulose /* 100ac1ad20fSSuzuki K Poulose * Verify that a secondary CPU is running the kernel at the same 101ac1ad20fSSuzuki K Poulose * EL as that of the boot CPU. 102ac1ad20fSSuzuki K Poulose */ 103ac1ad20fSSuzuki K Poulose void verify_cpu_run_el(void) 104ac1ad20fSSuzuki K Poulose { 105ac1ad20fSSuzuki K Poulose bool in_el2 = is_kernel_in_hyp_mode(); 106ac1ad20fSSuzuki K Poulose bool boot_cpu_el2 = is_boot_cpu_in_hyp_mode(); 107ac1ad20fSSuzuki K Poulose 108ac1ad20fSSuzuki K Poulose if (in_el2 ^ boot_cpu_el2) { 109ac1ad20fSSuzuki K Poulose pr_crit("CPU%d: mismatched Exception Level(EL%d) with boot CPU(EL%d)\n", 110ac1ad20fSSuzuki K Poulose smp_processor_id(), 111ac1ad20fSSuzuki K Poulose in_el2 ? 2 : 1, 112ac1ad20fSSuzuki K Poulose boot_cpu_el2 ? 2 : 1); 113ac1ad20fSSuzuki K Poulose cpu_panic_kernel(); 114ac1ad20fSSuzuki K Poulose } 115ac1ad20fSSuzuki K Poulose } 116ac1ad20fSSuzuki K Poulose 117ac1ad20fSSuzuki K Poulose #else 118ac1ad20fSSuzuki K Poulose static inline void save_boot_cpu_run_el(void) {} 119ac1ad20fSSuzuki K Poulose #endif 120ac1ad20fSSuzuki K Poulose 121bb905274SSuzuki K Poulose #ifdef CONFIG_HOTPLUG_CPU 122bb905274SSuzuki K Poulose static int op_cpu_kill(unsigned int cpu); 123bb905274SSuzuki K Poulose #else 124bb905274SSuzuki K Poulose static inline int op_cpu_kill(unsigned int cpu) 125bb905274SSuzuki K Poulose { 126bb905274SSuzuki K Poulose return -ENOSYS; 127bb905274SSuzuki K Poulose } 128bb905274SSuzuki K Poulose #endif 129bb905274SSuzuki K Poulose 130bb905274SSuzuki K Poulose 13108e875c1SCatalin Marinas /* 13208e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 13308e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 13408e875c1SCatalin Marinas */ 135b8c6453aSPaul Gortmaker static int boot_secondary(unsigned int cpu, struct task_struct *idle) 13608e875c1SCatalin Marinas { 137652af899SMark Rutland if (cpu_ops[cpu]->cpu_boot) 138652af899SMark Rutland return cpu_ops[cpu]->cpu_boot(cpu); 13908e875c1SCatalin Marinas 140652af899SMark Rutland return -EOPNOTSUPP; 14108e875c1SCatalin Marinas } 14208e875c1SCatalin Marinas 14308e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 14408e875c1SCatalin Marinas 145b8c6453aSPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *idle) 14608e875c1SCatalin Marinas { 14708e875c1SCatalin Marinas int ret; 148bb905274SSuzuki K Poulose long status; 14908e875c1SCatalin Marinas 15008e875c1SCatalin Marinas /* 15108e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 15208e875c1SCatalin Marinas * page tables. 15308e875c1SCatalin Marinas */ 154c02433ddSMark Rutland secondary_data.task = idle; 15508e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 156bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_MMU_OFF); 15708e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 15808e875c1SCatalin Marinas 15908e875c1SCatalin Marinas /* 16008e875c1SCatalin Marinas * Now bring the CPU into our world. 16108e875c1SCatalin Marinas */ 16208e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 16308e875c1SCatalin Marinas if (ret == 0) { 16408e875c1SCatalin Marinas /* 16508e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 16608e875c1SCatalin Marinas * time out. 16708e875c1SCatalin Marinas */ 16808e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 16908e875c1SCatalin Marinas msecs_to_jiffies(1000)); 17008e875c1SCatalin Marinas 17108e875c1SCatalin Marinas if (!cpu_online(cpu)) { 17208e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 17308e875c1SCatalin Marinas ret = -EIO; 17408e875c1SCatalin Marinas } 17508e875c1SCatalin Marinas } else { 17608e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 17708e875c1SCatalin Marinas } 17808e875c1SCatalin Marinas 179c02433ddSMark Rutland secondary_data.task = NULL; 18008e875c1SCatalin Marinas secondary_data.stack = NULL; 181bb905274SSuzuki K Poulose status = READ_ONCE(secondary_data.status); 182bb905274SSuzuki K Poulose if (ret && status) { 183bb905274SSuzuki K Poulose 184bb905274SSuzuki K Poulose if (status == CPU_MMU_OFF) 185bb905274SSuzuki K Poulose status = READ_ONCE(__early_cpu_boot_status); 186bb905274SSuzuki K Poulose 187bb905274SSuzuki K Poulose switch (status) { 188bb905274SSuzuki K Poulose default: 189bb905274SSuzuki K Poulose pr_err("CPU%u: failed in unknown state : 0x%lx\n", 190bb905274SSuzuki K Poulose cpu, status); 191bb905274SSuzuki K Poulose break; 192bb905274SSuzuki K Poulose case CPU_KILL_ME: 193bb905274SSuzuki K Poulose if (!op_cpu_kill(cpu)) { 194bb905274SSuzuki K Poulose pr_crit("CPU%u: died during early boot\n", cpu); 195bb905274SSuzuki K Poulose break; 196bb905274SSuzuki K Poulose } 197bb905274SSuzuki K Poulose /* Fall through */ 198bb905274SSuzuki K Poulose pr_crit("CPU%u: may not have shut down cleanly\n", cpu); 199bb905274SSuzuki K Poulose case CPU_STUCK_IN_KERNEL: 200bb905274SSuzuki K Poulose pr_crit("CPU%u: is stuck in kernel\n", cpu); 201bb905274SSuzuki K Poulose cpus_stuck_in_kernel++; 202bb905274SSuzuki K Poulose break; 203bb905274SSuzuki K Poulose case CPU_PANIC_KERNEL: 204bb905274SSuzuki K Poulose panic("CPU%u detected unsupported configuration\n", cpu); 205bb905274SSuzuki K Poulose } 206bb905274SSuzuki K Poulose } 20708e875c1SCatalin Marinas 20808e875c1SCatalin Marinas return ret; 20908e875c1SCatalin Marinas } 21008e875c1SCatalin Marinas 21108e875c1SCatalin Marinas /* 21208e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 21308e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 21408e875c1SCatalin Marinas */ 215b8c6453aSPaul Gortmaker asmlinkage void secondary_start_kernel(void) 21608e875c1SCatalin Marinas { 21708e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 218580efaa7SMark Rutland unsigned int cpu; 219580efaa7SMark Rutland 220580efaa7SMark Rutland cpu = task_cpu(current); 221580efaa7SMark Rutland set_my_cpu_offset(per_cpu_offset(cpu)); 22208e875c1SCatalin Marinas 22308e875c1SCatalin Marinas /* 22408e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 22508e875c1SCatalin Marinas * reference and switch to it. 22608e875c1SCatalin Marinas */ 227f1f10076SVegard Nossum mmgrab(mm); 22808e875c1SCatalin Marinas current->active_mm = mm; 22908e875c1SCatalin Marinas 23008e875c1SCatalin Marinas /* 23108e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 23208e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 23308e875c1SCatalin Marinas */ 2349e8e865bSMark Rutland cpu_uninstall_idmap(); 23508e875c1SCatalin Marinas 23608e875c1SCatalin Marinas preempt_disable(); 23708e875c1SCatalin Marinas trace_hardirqs_off(); 23808e875c1SCatalin Marinas 239dbb4e152SSuzuki K. Poulose /* 240dbb4e152SSuzuki K. Poulose * If the system has established the capabilities, make sure 241dbb4e152SSuzuki K. Poulose * this CPU ticks all of those. If it doesn't, the CPU will 242dbb4e152SSuzuki K. Poulose * fail to come online. 243dbb4e152SSuzuki K. Poulose */ 244c47a1900SSuzuki K Poulose check_local_cpu_capabilities(); 245dbb4e152SSuzuki K. Poulose 246652af899SMark Rutland if (cpu_ops[cpu]->cpu_postboot) 247652af899SMark Rutland cpu_ops[cpu]->cpu_postboot(); 24808e875c1SCatalin Marinas 24908e875c1SCatalin Marinas /* 250df857416SMark Rutland * Log the CPU info before it is marked online and might get read. 251df857416SMark Rutland */ 252df857416SMark Rutland cpuinfo_store_cpu(); 253df857416SMark Rutland 254df857416SMark Rutland /* 2557ade67b5SMarc Zyngier * Enable GIC and timers. 2567ade67b5SMarc Zyngier */ 2577ade67b5SMarc Zyngier notify_cpu_starting(cpu); 2587ade67b5SMarc Zyngier 259c18df0adSDavid Daney store_cpu_topology(cpu); 260f6e763b9SMark Brown 2617ade67b5SMarc Zyngier /* 26208e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 26308e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 26408e875c1SCatalin Marinas * before we continue. 26508e875c1SCatalin Marinas */ 26664f17818SSuzuki K. Poulose pr_info("CPU%u: Booted secondary processor [%08x]\n", 26764f17818SSuzuki K. Poulose cpu, read_cpuid_id()); 268bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_BOOT_SUCCESS); 26908e875c1SCatalin Marinas set_cpu_online(cpu, true); 270b3770b32SWill Deacon complete(&cpu_running); 27108e875c1SCatalin Marinas 27253ae3acdSCatalin Marinas local_irq_enable(); 273b3bf6aa7SCatalin Marinas local_async_enable(); 27453ae3acdSCatalin Marinas 27553ae3acdSCatalin Marinas /* 27608e875c1SCatalin Marinas * OK, it's off to the idle thread for us 27708e875c1SCatalin Marinas */ 278fc6d73d6SThomas Gleixner cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 27908e875c1SCatalin Marinas } 28008e875c1SCatalin Marinas 2819327e2c6SMark Rutland #ifdef CONFIG_HOTPLUG_CPU 2829327e2c6SMark Rutland static int op_cpu_disable(unsigned int cpu) 2839327e2c6SMark Rutland { 2849327e2c6SMark Rutland /* 2859327e2c6SMark Rutland * If we don't have a cpu_die method, abort before we reach the point 2869327e2c6SMark Rutland * of no return. CPU0 may not have an cpu_ops, so test for it. 2879327e2c6SMark Rutland */ 2889327e2c6SMark Rutland if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) 2899327e2c6SMark Rutland return -EOPNOTSUPP; 2909327e2c6SMark Rutland 2919327e2c6SMark Rutland /* 2929327e2c6SMark Rutland * We may need to abort a hot unplug for some other mechanism-specific 2939327e2c6SMark Rutland * reason. 2949327e2c6SMark Rutland */ 2959327e2c6SMark Rutland if (cpu_ops[cpu]->cpu_disable) 2969327e2c6SMark Rutland return cpu_ops[cpu]->cpu_disable(cpu); 2979327e2c6SMark Rutland 2989327e2c6SMark Rutland return 0; 2999327e2c6SMark Rutland } 3009327e2c6SMark Rutland 3019327e2c6SMark Rutland /* 3029327e2c6SMark Rutland * __cpu_disable runs on the processor to be shutdown. 3039327e2c6SMark Rutland */ 3049327e2c6SMark Rutland int __cpu_disable(void) 3059327e2c6SMark Rutland { 3069327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 3079327e2c6SMark Rutland int ret; 3089327e2c6SMark Rutland 3099327e2c6SMark Rutland ret = op_cpu_disable(cpu); 3109327e2c6SMark Rutland if (ret) 3119327e2c6SMark Rutland return ret; 3129327e2c6SMark Rutland 3139327e2c6SMark Rutland /* 3149327e2c6SMark Rutland * Take this CPU offline. Once we clear this, we can't return, 3159327e2c6SMark Rutland * and we must not schedule until we're ready to give up the cpu. 3169327e2c6SMark Rutland */ 3179327e2c6SMark Rutland set_cpu_online(cpu, false); 3189327e2c6SMark Rutland 3199327e2c6SMark Rutland /* 3209327e2c6SMark Rutland * OK - migrate IRQs away from this CPU 3219327e2c6SMark Rutland */ 322217d453dSYang Yingliang irq_migrate_all_off_this_cpu(); 323217d453dSYang Yingliang 3249327e2c6SMark Rutland return 0; 3259327e2c6SMark Rutland } 3269327e2c6SMark Rutland 327c814ca02SAshwin Chaugule static int op_cpu_kill(unsigned int cpu) 328c814ca02SAshwin Chaugule { 329c814ca02SAshwin Chaugule /* 330c814ca02SAshwin Chaugule * If we have no means of synchronising with the dying CPU, then assume 331c814ca02SAshwin Chaugule * that it is really dead. We can only wait for an arbitrary length of 332c814ca02SAshwin Chaugule * time and hope that it's dead, so let's skip the wait and just hope. 333c814ca02SAshwin Chaugule */ 334c814ca02SAshwin Chaugule if (!cpu_ops[cpu]->cpu_kill) 3356b99c68cSMark Rutland return 0; 336c814ca02SAshwin Chaugule 337c814ca02SAshwin Chaugule return cpu_ops[cpu]->cpu_kill(cpu); 338c814ca02SAshwin Chaugule } 339c814ca02SAshwin Chaugule 3409327e2c6SMark Rutland /* 3419327e2c6SMark Rutland * called on the thread which is asking for a CPU to be shutdown - 3429327e2c6SMark Rutland * waits until shutdown has completed, or it is timed out. 3439327e2c6SMark Rutland */ 3449327e2c6SMark Rutland void __cpu_die(unsigned int cpu) 3459327e2c6SMark Rutland { 3466b99c68cSMark Rutland int err; 3476b99c68cSMark Rutland 34805981277SPaul E. McKenney if (!cpu_wait_death(cpu, 5)) { 3499327e2c6SMark Rutland pr_crit("CPU%u: cpu didn't die\n", cpu); 3509327e2c6SMark Rutland return; 3519327e2c6SMark Rutland } 3529327e2c6SMark Rutland pr_notice("CPU%u: shutdown\n", cpu); 353c814ca02SAshwin Chaugule 354c814ca02SAshwin Chaugule /* 355c814ca02SAshwin Chaugule * Now that the dying CPU is beyond the point of no return w.r.t. 356c814ca02SAshwin Chaugule * in-kernel synchronisation, try to get the firwmare to help us to 357c814ca02SAshwin Chaugule * verify that it has really left the kernel before we consider 358c814ca02SAshwin Chaugule * clobbering anything it might still be using. 359c814ca02SAshwin Chaugule */ 3606b99c68cSMark Rutland err = op_cpu_kill(cpu); 3616b99c68cSMark Rutland if (err) 3626b99c68cSMark Rutland pr_warn("CPU%d may not have shut down cleanly: %d\n", 3636b99c68cSMark Rutland cpu, err); 3649327e2c6SMark Rutland } 3659327e2c6SMark Rutland 3669327e2c6SMark Rutland /* 3679327e2c6SMark Rutland * Called from the idle thread for the CPU which has been shutdown. 3689327e2c6SMark Rutland * 3699327e2c6SMark Rutland * Note that we disable IRQs here, but do not re-enable them 3709327e2c6SMark Rutland * before returning to the caller. This is also the behaviour 3719327e2c6SMark Rutland * of the other hotplug-cpu capable cores, so presumably coming 3729327e2c6SMark Rutland * out of idle fixes this. 3739327e2c6SMark Rutland */ 3749327e2c6SMark Rutland void cpu_die(void) 3759327e2c6SMark Rutland { 3769327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 3779327e2c6SMark Rutland 3789327e2c6SMark Rutland idle_task_exit(); 3799327e2c6SMark Rutland 3809327e2c6SMark Rutland local_irq_disable(); 3819327e2c6SMark Rutland 3829327e2c6SMark Rutland /* Tell __cpu_die() that this CPU is now safe to dispose of */ 38305981277SPaul E. McKenney (void)cpu_report_death(); 3849327e2c6SMark Rutland 3859327e2c6SMark Rutland /* 3869327e2c6SMark Rutland * Actually shutdown the CPU. This must never fail. The specific hotplug 3879327e2c6SMark Rutland * mechanism must perform all required cache maintenance to ensure that 3889327e2c6SMark Rutland * no dirty lines are lost in the process of shutting down the CPU. 3899327e2c6SMark Rutland */ 3909327e2c6SMark Rutland cpu_ops[cpu]->cpu_die(cpu); 3919327e2c6SMark Rutland 3929327e2c6SMark Rutland BUG(); 3939327e2c6SMark Rutland } 3949327e2c6SMark Rutland #endif 3959327e2c6SMark Rutland 396fce6361fSSuzuki K Poulose /* 397fce6361fSSuzuki K Poulose * Kill the calling secondary CPU, early in bringup before it is turned 398fce6361fSSuzuki K Poulose * online. 399fce6361fSSuzuki K Poulose */ 400fce6361fSSuzuki K Poulose void cpu_die_early(void) 401fce6361fSSuzuki K Poulose { 402fce6361fSSuzuki K Poulose int cpu = smp_processor_id(); 403fce6361fSSuzuki K Poulose 404fce6361fSSuzuki K Poulose pr_crit("CPU%d: will not boot\n", cpu); 405fce6361fSSuzuki K Poulose 406fce6361fSSuzuki K Poulose /* Mark this CPU absent */ 407fce6361fSSuzuki K Poulose set_cpu_present(cpu, 0); 408fce6361fSSuzuki K Poulose 409fce6361fSSuzuki K Poulose #ifdef CONFIG_HOTPLUG_CPU 410bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_KILL_ME); 411fce6361fSSuzuki K Poulose /* Check if we can park ourselves */ 412fce6361fSSuzuki K Poulose if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_die) 413fce6361fSSuzuki K Poulose cpu_ops[cpu]->cpu_die(cpu); 414fce6361fSSuzuki K Poulose #endif 415bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_STUCK_IN_KERNEL); 416fce6361fSSuzuki K Poulose 417fce6361fSSuzuki K Poulose cpu_park_loop(); 418fce6361fSSuzuki K Poulose } 419fce6361fSSuzuki K Poulose 420377bcff9SJonas Rabenstein static void __init hyp_mode_check(void) 421377bcff9SJonas Rabenstein { 422377bcff9SJonas Rabenstein if (is_hyp_mode_available()) 423377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL2\n"); 424377bcff9SJonas Rabenstein else if (is_hyp_mode_mismatched()) 425377bcff9SJonas Rabenstein WARN_TAINT(1, TAINT_CPU_OUT_OF_SPEC, 426377bcff9SJonas Rabenstein "CPU: CPUs started in inconsistent modes"); 427377bcff9SJonas Rabenstein else 428377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL1\n"); 429377bcff9SJonas Rabenstein } 430377bcff9SJonas Rabenstein 43108e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 43208e875c1SCatalin Marinas { 433326b16dbSWill Deacon pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); 4343a75578eSSuzuki K. Poulose setup_cpu_features(); 435377bcff9SJonas Rabenstein hyp_mode_check(); 436377bcff9SJonas Rabenstein apply_alternatives_all(); 43708e875c1SCatalin Marinas } 43808e875c1SCatalin Marinas 43908e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 44008e875c1SCatalin Marinas { 4419113c2aaSSuzuki K Poulose set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 442efd9e03fSCatalin Marinas /* 443efd9e03fSCatalin Marinas * Initialise the static keys early as they may be enabled by the 444efd9e03fSCatalin Marinas * cpufeature code. 445efd9e03fSCatalin Marinas */ 446efd9e03fSCatalin Marinas jump_label_init(); 4474b998ff1SSuzuki K. Poulose cpuinfo_store_boot_cpu(); 448ac1ad20fSSuzuki K Poulose save_boot_cpu_run_el(); 449c47a1900SSuzuki K Poulose /* 450c47a1900SSuzuki K Poulose * Run the errata work around checks on the boot CPU, once we have 451c47a1900SSuzuki K Poulose * initialised the cpu feature infrastructure from 452c47a1900SSuzuki K Poulose * cpuinfo_store_boot_cpu() above. 453c47a1900SSuzuki K Poulose */ 454c47a1900SSuzuki K Poulose update_cpu_errata_workarounds(); 45508e875c1SCatalin Marinas } 45608e875c1SCatalin Marinas 4570f078336SLorenzo Pieralisi static u64 __init of_get_cpu_mpidr(struct device_node *dn) 4580f078336SLorenzo Pieralisi { 4590f078336SLorenzo Pieralisi const __be32 *cell; 4600f078336SLorenzo Pieralisi u64 hwid; 4610f078336SLorenzo Pieralisi 4620f078336SLorenzo Pieralisi /* 4630f078336SLorenzo Pieralisi * A cpu node with missing "reg" property is 4640f078336SLorenzo Pieralisi * considered invalid to build a cpu_logical_map 4650f078336SLorenzo Pieralisi * entry. 4660f078336SLorenzo Pieralisi */ 4670f078336SLorenzo Pieralisi cell = of_get_property(dn, "reg", NULL); 4680f078336SLorenzo Pieralisi if (!cell) { 4690f078336SLorenzo Pieralisi pr_err("%s: missing reg property\n", dn->full_name); 4700f078336SLorenzo Pieralisi return INVALID_HWID; 4710f078336SLorenzo Pieralisi } 4720f078336SLorenzo Pieralisi 4730f078336SLorenzo Pieralisi hwid = of_read_number(cell, of_n_addr_cells(dn)); 4740f078336SLorenzo Pieralisi /* 4750f078336SLorenzo Pieralisi * Non affinity bits must be set to 0 in the DT 4760f078336SLorenzo Pieralisi */ 4770f078336SLorenzo Pieralisi if (hwid & ~MPIDR_HWID_BITMASK) { 4780f078336SLorenzo Pieralisi pr_err("%s: invalid reg property\n", dn->full_name); 4790f078336SLorenzo Pieralisi return INVALID_HWID; 4800f078336SLorenzo Pieralisi } 4810f078336SLorenzo Pieralisi return hwid; 4820f078336SLorenzo Pieralisi } 4830f078336SLorenzo Pieralisi 4840f078336SLorenzo Pieralisi /* 4850f078336SLorenzo Pieralisi * Duplicate MPIDRs are a recipe for disaster. Scan all initialized 4860f078336SLorenzo Pieralisi * entries and check for duplicates. If any is found just ignore the 4870f078336SLorenzo Pieralisi * cpu. cpu_logical_map was initialized to INVALID_HWID to avoid 4880f078336SLorenzo Pieralisi * matching valid MPIDR values. 4890f078336SLorenzo Pieralisi */ 4900f078336SLorenzo Pieralisi static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid) 4910f078336SLorenzo Pieralisi { 4920f078336SLorenzo Pieralisi unsigned int i; 4930f078336SLorenzo Pieralisi 4940f078336SLorenzo Pieralisi for (i = 1; (i < cpu) && (i < NR_CPUS); i++) 4950f078336SLorenzo Pieralisi if (cpu_logical_map(i) == hwid) 4960f078336SLorenzo Pieralisi return true; 4970f078336SLorenzo Pieralisi return false; 4980f078336SLorenzo Pieralisi } 4990f078336SLorenzo Pieralisi 50008e875c1SCatalin Marinas /* 501819a8826SLorenzo Pieralisi * Initialize cpu operations for a logical cpu and 502819a8826SLorenzo Pieralisi * set it in the possible mask on success 503819a8826SLorenzo Pieralisi */ 504819a8826SLorenzo Pieralisi static int __init smp_cpu_setup(int cpu) 505819a8826SLorenzo Pieralisi { 506819a8826SLorenzo Pieralisi if (cpu_read_ops(cpu)) 507819a8826SLorenzo Pieralisi return -ENODEV; 508819a8826SLorenzo Pieralisi 509819a8826SLorenzo Pieralisi if (cpu_ops[cpu]->cpu_init(cpu)) 510819a8826SLorenzo Pieralisi return -ENODEV; 511819a8826SLorenzo Pieralisi 512819a8826SLorenzo Pieralisi set_cpu_possible(cpu, true); 513819a8826SLorenzo Pieralisi 514819a8826SLorenzo Pieralisi return 0; 515819a8826SLorenzo Pieralisi } 516819a8826SLorenzo Pieralisi 5170f078336SLorenzo Pieralisi static bool bootcpu_valid __initdata; 5180f078336SLorenzo Pieralisi static unsigned int cpu_count = 1; 5190f078336SLorenzo Pieralisi 5200f078336SLorenzo Pieralisi #ifdef CONFIG_ACPI 5210f078336SLorenzo Pieralisi /* 5220f078336SLorenzo Pieralisi * acpi_map_gic_cpu_interface - parse processor MADT entry 5230f078336SLorenzo Pieralisi * 5240f078336SLorenzo Pieralisi * Carry out sanity checks on MADT processor entry and initialize 5250f078336SLorenzo Pieralisi * cpu_logical_map on success 5260f078336SLorenzo Pieralisi */ 5270f078336SLorenzo Pieralisi static void __init 5280f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) 5290f078336SLorenzo Pieralisi { 5300f078336SLorenzo Pieralisi u64 hwid = processor->arm_mpidr; 5310f078336SLorenzo Pieralisi 532f9058929SHanjun Guo if (!(processor->flags & ACPI_MADT_ENABLED)) { 533f9058929SHanjun Guo pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid); 5340f078336SLorenzo Pieralisi return; 5350f078336SLorenzo Pieralisi } 5360f078336SLorenzo Pieralisi 537f9058929SHanjun Guo if (hwid & ~MPIDR_HWID_BITMASK || hwid == INVALID_HWID) { 538f9058929SHanjun Guo pr_err("skipping CPU entry with invalid MPIDR 0x%llx\n", hwid); 5390f078336SLorenzo Pieralisi return; 5400f078336SLorenzo Pieralisi } 5410f078336SLorenzo Pieralisi 5420f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 5430f078336SLorenzo Pieralisi pr_err("duplicate CPU MPIDR 0x%llx in MADT\n", hwid); 5440f078336SLorenzo Pieralisi return; 5450f078336SLorenzo Pieralisi } 5460f078336SLorenzo Pieralisi 5470f078336SLorenzo Pieralisi /* Check if GICC structure of boot CPU is available in the MADT */ 5480f078336SLorenzo Pieralisi if (cpu_logical_map(0) == hwid) { 5490f078336SLorenzo Pieralisi if (bootcpu_valid) { 5500f078336SLorenzo Pieralisi pr_err("duplicate boot CPU MPIDR: 0x%llx in MADT\n", 5510f078336SLorenzo Pieralisi hwid); 5520f078336SLorenzo Pieralisi return; 5530f078336SLorenzo Pieralisi } 5540f078336SLorenzo Pieralisi bootcpu_valid = true; 555baa5567cSLorenzo Pieralisi early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid)); 5560f078336SLorenzo Pieralisi return; 5570f078336SLorenzo Pieralisi } 5580f078336SLorenzo Pieralisi 5590f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 5600f078336SLorenzo Pieralisi return; 5610f078336SLorenzo Pieralisi 5620f078336SLorenzo Pieralisi /* map the logical cpu id to cpu MPIDR */ 5630f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 5640f078336SLorenzo Pieralisi 5655e89c55eSLorenzo Pieralisi /* 5665e89c55eSLorenzo Pieralisi * Set-up the ACPI parking protocol cpu entries 5675e89c55eSLorenzo Pieralisi * while initializing the cpu_logical_map to 5685e89c55eSLorenzo Pieralisi * avoid parsing MADT entries multiple times for 5695e89c55eSLorenzo Pieralisi * nothing (ie a valid cpu_logical_map entry should 5705e89c55eSLorenzo Pieralisi * contain a valid parking protocol data set to 5715e89c55eSLorenzo Pieralisi * initialize the cpu if the parking protocol is 5725e89c55eSLorenzo Pieralisi * the only available enable method). 5735e89c55eSLorenzo Pieralisi */ 5745e89c55eSLorenzo Pieralisi acpi_set_mailbox_entry(cpu_count, processor); 5755e89c55eSLorenzo Pieralisi 576d8b47fcaSHanjun Guo early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid)); 577d8b47fcaSHanjun Guo 5780f078336SLorenzo Pieralisi cpu_count++; 5790f078336SLorenzo Pieralisi } 5800f078336SLorenzo Pieralisi 5810f078336SLorenzo Pieralisi static int __init 5820f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, 5830f078336SLorenzo Pieralisi const unsigned long end) 5840f078336SLorenzo Pieralisi { 5850f078336SLorenzo Pieralisi struct acpi_madt_generic_interrupt *processor; 5860f078336SLorenzo Pieralisi 5870f078336SLorenzo Pieralisi processor = (struct acpi_madt_generic_interrupt *)header; 58899e3e3aeSAl Stone if (BAD_MADT_GICC_ENTRY(processor, end)) 5890f078336SLorenzo Pieralisi return -EINVAL; 5900f078336SLorenzo Pieralisi 5910f078336SLorenzo Pieralisi acpi_table_print_madt_entry(header); 5920f078336SLorenzo Pieralisi 5930f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(processor); 5940f078336SLorenzo Pieralisi 5950f078336SLorenzo Pieralisi return 0; 5960f078336SLorenzo Pieralisi } 5970f078336SLorenzo Pieralisi #else 5980f078336SLorenzo Pieralisi #define acpi_table_parse_madt(...) do { } while (0) 5990f078336SLorenzo Pieralisi #endif 6000f078336SLorenzo Pieralisi 601819a8826SLorenzo Pieralisi /* 6024c7aa002SJavi Merino * Enumerate the possible CPU set from the device tree and build the 6034c7aa002SJavi Merino * cpu logical map array containing MPIDR values related to logical 6044c7aa002SJavi Merino * cpus. Assumes that cpu_logical_map(0) has already been initialized. 60508e875c1SCatalin Marinas */ 60629b8302bSJisheng Zhang static void __init of_parse_and_init_cpus(void) 60708e875c1SCatalin Marinas { 6083d29a9a0SDmitry Torokhov struct device_node *dn; 60908e875c1SCatalin Marinas 6103d29a9a0SDmitry Torokhov for_each_node_by_type(dn, "cpu") { 6110f078336SLorenzo Pieralisi u64 hwid = of_get_cpu_mpidr(dn); 6124c7aa002SJavi Merino 6130f078336SLorenzo Pieralisi if (hwid == INVALID_HWID) 6144c7aa002SJavi Merino goto next; 6154c7aa002SJavi Merino 6160f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 6174c7aa002SJavi Merino pr_err("%s: duplicate cpu reg properties in the DT\n", 6184c7aa002SJavi Merino dn->full_name); 6194c7aa002SJavi Merino goto next; 6204c7aa002SJavi Merino } 6214c7aa002SJavi Merino 6224c7aa002SJavi Merino /* 6234c7aa002SJavi Merino * The numbering scheme requires that the boot CPU 6244c7aa002SJavi Merino * must be assigned logical id 0. Record it so that 6254c7aa002SJavi Merino * the logical map built from DT is validated and can 6264c7aa002SJavi Merino * be used. 6274c7aa002SJavi Merino */ 6284c7aa002SJavi Merino if (hwid == cpu_logical_map(0)) { 6294c7aa002SJavi Merino if (bootcpu_valid) { 6304c7aa002SJavi Merino pr_err("%s: duplicate boot cpu reg property in DT\n", 6314c7aa002SJavi Merino dn->full_name); 6324c7aa002SJavi Merino goto next; 6334c7aa002SJavi Merino } 6344c7aa002SJavi Merino 6354c7aa002SJavi Merino bootcpu_valid = true; 6367ba5f605SZhen Lei early_map_cpu_to_node(0, of_node_to_nid(dn)); 6374c7aa002SJavi Merino 6384c7aa002SJavi Merino /* 6394c7aa002SJavi Merino * cpu_logical_map has already been 6404c7aa002SJavi Merino * initialized and the boot cpu doesn't need 6414c7aa002SJavi Merino * the enable-method so continue without 6424c7aa002SJavi Merino * incrementing cpu. 6434c7aa002SJavi Merino */ 6444c7aa002SJavi Merino continue; 6454c7aa002SJavi Merino } 6464c7aa002SJavi Merino 6470f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 64808e875c1SCatalin Marinas goto next; 64908e875c1SCatalin Marinas 6504c7aa002SJavi Merino pr_debug("cpu logical map 0x%llx\n", hwid); 6510f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 6521a2db300SGanapatrao Kulkarni 6531a2db300SGanapatrao Kulkarni early_map_cpu_to_node(cpu_count, of_node_to_nid(dn)); 65408e875c1SCatalin Marinas next: 6550f078336SLorenzo Pieralisi cpu_count++; 6560f078336SLorenzo Pieralisi } 65708e875c1SCatalin Marinas } 65808e875c1SCatalin Marinas 6590f078336SLorenzo Pieralisi /* 6600f078336SLorenzo Pieralisi * Enumerate the possible CPU set from the device tree or ACPI and build the 6610f078336SLorenzo Pieralisi * cpu logical map array containing MPIDR values related to logical 6620f078336SLorenzo Pieralisi * cpus. Assumes that cpu_logical_map(0) has already been initialized. 6630f078336SLorenzo Pieralisi */ 6640f078336SLorenzo Pieralisi void __init smp_init_cpus(void) 6650f078336SLorenzo Pieralisi { 6660f078336SLorenzo Pieralisi int i; 6670f078336SLorenzo Pieralisi 6680f078336SLorenzo Pieralisi if (acpi_disabled) 6690f078336SLorenzo Pieralisi of_parse_and_init_cpus(); 6700f078336SLorenzo Pieralisi else 6710f078336SLorenzo Pieralisi /* 6720f078336SLorenzo Pieralisi * do a walk of MADT to determine how many CPUs 6730f078336SLorenzo Pieralisi * we have including disabled CPUs, and get information 6740f078336SLorenzo Pieralisi * we need for SMP init 6750f078336SLorenzo Pieralisi */ 6760f078336SLorenzo Pieralisi acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, 6770f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface, 0); 6780f078336SLorenzo Pieralisi 67950ee91bdSKefeng Wang if (cpu_count > nr_cpu_ids) 68050ee91bdSKefeng Wang pr_warn("Number of cores (%d) exceeds configured maximum of %d - clipping\n", 68150ee91bdSKefeng Wang cpu_count, nr_cpu_ids); 6824c7aa002SJavi Merino 6834c7aa002SJavi Merino if (!bootcpu_valid) { 6840f078336SLorenzo Pieralisi pr_err("missing boot CPU MPIDR, not enabling secondaries\n"); 6854c7aa002SJavi Merino return; 6864c7aa002SJavi Merino } 6874c7aa002SJavi Merino 6884c7aa002SJavi Merino /* 689819a8826SLorenzo Pieralisi * We need to set the cpu_logical_map entries before enabling 690819a8826SLorenzo Pieralisi * the cpus so that cpu processor description entries (DT cpu nodes 691819a8826SLorenzo Pieralisi * and ACPI MADT entries) can be retrieved by matching the cpu hwid 692819a8826SLorenzo Pieralisi * with entries in cpu_logical_map while initializing the cpus. 693819a8826SLorenzo Pieralisi * If the cpu set-up fails, invalidate the cpu_logical_map entry. 6944c7aa002SJavi Merino */ 69550ee91bdSKefeng Wang for (i = 1; i < nr_cpu_ids; i++) { 696819a8826SLorenzo Pieralisi if (cpu_logical_map(i) != INVALID_HWID) { 697819a8826SLorenzo Pieralisi if (smp_cpu_setup(i)) 698819a8826SLorenzo Pieralisi cpu_logical_map(i) = INVALID_HWID; 699819a8826SLorenzo Pieralisi } 700819a8826SLorenzo Pieralisi } 70108e875c1SCatalin Marinas } 70208e875c1SCatalin Marinas 70308e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 70408e875c1SCatalin Marinas { 705cd1aebf5SMark Rutland int err; 70644dbcc93SSuzuki K Poulose unsigned int cpu; 707c18df0adSDavid Daney unsigned int this_cpu; 70808e875c1SCatalin Marinas 709f6e763b9SMark Brown init_cpu_topology(); 710f6e763b9SMark Brown 711c18df0adSDavid Daney this_cpu = smp_processor_id(); 712c18df0adSDavid Daney store_cpu_topology(this_cpu); 713c18df0adSDavid Daney numa_store_cpu_info(this_cpu); 714f6e763b9SMark Brown 71508e875c1SCatalin Marinas /* 716e75118a7SSuzuki K Poulose * If UP is mandated by "nosmp" (which implies "maxcpus=0"), don't set 717e75118a7SSuzuki K Poulose * secondary CPUs present. 718e75118a7SSuzuki K Poulose */ 719e75118a7SSuzuki K Poulose if (max_cpus == 0) 720e75118a7SSuzuki K Poulose return; 721e75118a7SSuzuki K Poulose 722e75118a7SSuzuki K Poulose /* 72308e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 72408e875c1SCatalin Marinas * actually populated at the present time) and release the 72508e875c1SCatalin Marinas * secondaries from the bootloader. 72608e875c1SCatalin Marinas */ 72708e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 72808e875c1SCatalin Marinas 72957c82954SMark Rutland per_cpu(cpu_number, cpu) = cpu; 73057c82954SMark Rutland 731d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 73208e875c1SCatalin Marinas continue; 73308e875c1SCatalin Marinas 734cd1aebf5SMark Rutland if (!cpu_ops[cpu]) 735d329de3fSMarc Zyngier continue; 736d329de3fSMarc Zyngier 737cd1aebf5SMark Rutland err = cpu_ops[cpu]->cpu_prepare(cpu); 738d329de3fSMarc Zyngier if (err) 739d329de3fSMarc Zyngier continue; 74008e875c1SCatalin Marinas 74108e875c1SCatalin Marinas set_cpu_present(cpu, true); 742c18df0adSDavid Daney numa_store_cpu_info(cpu); 74308e875c1SCatalin Marinas } 74408e875c1SCatalin Marinas } 74508e875c1SCatalin Marinas 74636310736SFrederic Weisbecker void (*__smp_cross_call)(const struct cpumask *, unsigned int); 74708e875c1SCatalin Marinas 74808e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 74908e875c1SCatalin Marinas { 75045ed695aSNicolas Pitre __smp_cross_call = fn; 75108e875c1SCatalin Marinas } 75208e875c1SCatalin Marinas 75345ed695aSNicolas Pitre static const char *ipi_types[NR_IPI] __tracepoint_string = { 75445ed695aSNicolas Pitre #define S(x,s) [x] = s 75508e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 75608e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 75708e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 7581f85008eSLorenzo Pieralisi S(IPI_TIMER, "Timer broadcast interrupts"), 759eb631bb5SLarry Bassel S(IPI_IRQ_WORK, "IRQ work interrupts"), 7605e89c55eSLorenzo Pieralisi S(IPI_WAKEUP, "CPU wake-up interrupts"), 76108e875c1SCatalin Marinas }; 76208e875c1SCatalin Marinas 76345ed695aSNicolas Pitre static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) 76445ed695aSNicolas Pitre { 76545ed695aSNicolas Pitre trace_ipi_raise(target, ipi_types[ipinr]); 76645ed695aSNicolas Pitre __smp_cross_call(target, ipinr); 76745ed695aSNicolas Pitre } 76845ed695aSNicolas Pitre 76908e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 77008e875c1SCatalin Marinas { 77108e875c1SCatalin Marinas unsigned int cpu, i; 77208e875c1SCatalin Marinas 77308e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 77445ed695aSNicolas Pitre seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, 77508e875c1SCatalin Marinas prec >= 4 ? " " : ""); 77667317c26SSudeep KarkadaNagesha for_each_online_cpu(cpu) 77708e875c1SCatalin Marinas seq_printf(p, "%10u ", 77808e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 77908e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 78008e875c1SCatalin Marinas } 78108e875c1SCatalin Marinas } 78208e875c1SCatalin Marinas 78308e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 78408e875c1SCatalin Marinas { 78508e875c1SCatalin Marinas u64 sum = 0; 78608e875c1SCatalin Marinas int i; 78708e875c1SCatalin Marinas 78808e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 78908e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 79008e875c1SCatalin Marinas 79108e875c1SCatalin Marinas return sum; 79208e875c1SCatalin Marinas } 79308e875c1SCatalin Marinas 79445ed695aSNicolas Pitre void arch_send_call_function_ipi_mask(const struct cpumask *mask) 79545ed695aSNicolas Pitre { 79645ed695aSNicolas Pitre smp_cross_call(mask, IPI_CALL_FUNC); 79745ed695aSNicolas Pitre } 79845ed695aSNicolas Pitre 79945ed695aSNicolas Pitre void arch_send_call_function_single_ipi(int cpu) 80045ed695aSNicolas Pitre { 8010aaf0daeSJiang Liu smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC); 80245ed695aSNicolas Pitre } 80345ed695aSNicolas Pitre 8045e89c55eSLorenzo Pieralisi #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL 8055e89c55eSLorenzo Pieralisi void arch_send_wakeup_ipi_mask(const struct cpumask *mask) 8065e89c55eSLorenzo Pieralisi { 8075e89c55eSLorenzo Pieralisi smp_cross_call(mask, IPI_WAKEUP); 8085e89c55eSLorenzo Pieralisi } 8095e89c55eSLorenzo Pieralisi #endif 8105e89c55eSLorenzo Pieralisi 81145ed695aSNicolas Pitre #ifdef CONFIG_IRQ_WORK 81245ed695aSNicolas Pitre void arch_irq_work_raise(void) 81345ed695aSNicolas Pitre { 81445ed695aSNicolas Pitre if (__smp_cross_call) 81545ed695aSNicolas Pitre smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); 81645ed695aSNicolas Pitre } 81745ed695aSNicolas Pitre #endif 81845ed695aSNicolas Pitre 81908e875c1SCatalin Marinas /* 82008e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 82108e875c1SCatalin Marinas */ 82208e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 82308e875c1SCatalin Marinas { 82408e875c1SCatalin Marinas set_cpu_online(cpu, false); 82508e875c1SCatalin Marinas 82608e875c1SCatalin Marinas local_irq_disable(); 82708e875c1SCatalin Marinas 82808e875c1SCatalin Marinas while (1) 82908e875c1SCatalin Marinas cpu_relax(); 83008e875c1SCatalin Marinas } 83108e875c1SCatalin Marinas 83208e875c1SCatalin Marinas /* 83308e875c1SCatalin Marinas * Main handler for inter-processor interrupts 83408e875c1SCatalin Marinas */ 83508e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 83608e875c1SCatalin Marinas { 83708e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 83808e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 83908e875c1SCatalin Marinas 84045ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) { 841be081d9bSStephen Boyd trace_ipi_entry_rcuidle(ipi_types[ipinr]); 84245ed695aSNicolas Pitre __inc_irq_stat(cpu, ipi_irqs[ipinr]); 84345ed695aSNicolas Pitre } 84408e875c1SCatalin Marinas 84508e875c1SCatalin Marinas switch (ipinr) { 84608e875c1SCatalin Marinas case IPI_RESCHEDULE: 84708e875c1SCatalin Marinas scheduler_ipi(); 84808e875c1SCatalin Marinas break; 84908e875c1SCatalin Marinas 85008e875c1SCatalin Marinas case IPI_CALL_FUNC: 85108e875c1SCatalin Marinas irq_enter(); 85208e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 85308e875c1SCatalin Marinas irq_exit(); 85408e875c1SCatalin Marinas break; 85508e875c1SCatalin Marinas 85608e875c1SCatalin Marinas case IPI_CPU_STOP: 85708e875c1SCatalin Marinas irq_enter(); 85808e875c1SCatalin Marinas ipi_cpu_stop(cpu); 85908e875c1SCatalin Marinas irq_exit(); 86008e875c1SCatalin Marinas break; 86108e875c1SCatalin Marinas 8621f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 8631f85008eSLorenzo Pieralisi case IPI_TIMER: 8641f85008eSLorenzo Pieralisi irq_enter(); 8651f85008eSLorenzo Pieralisi tick_receive_broadcast(); 8661f85008eSLorenzo Pieralisi irq_exit(); 8671f85008eSLorenzo Pieralisi break; 8681f85008eSLorenzo Pieralisi #endif 8691f85008eSLorenzo Pieralisi 870eb631bb5SLarry Bassel #ifdef CONFIG_IRQ_WORK 871eb631bb5SLarry Bassel case IPI_IRQ_WORK: 872eb631bb5SLarry Bassel irq_enter(); 873eb631bb5SLarry Bassel irq_work_run(); 874eb631bb5SLarry Bassel irq_exit(); 875eb631bb5SLarry Bassel break; 876eb631bb5SLarry Bassel #endif 877eb631bb5SLarry Bassel 8785e89c55eSLorenzo Pieralisi #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL 8795e89c55eSLorenzo Pieralisi case IPI_WAKEUP: 8805e89c55eSLorenzo Pieralisi WARN_ONCE(!acpi_parking_protocol_valid(cpu), 8815e89c55eSLorenzo Pieralisi "CPU%u: Wake-up IPI outside the ACPI parking protocol\n", 8825e89c55eSLorenzo Pieralisi cpu); 8835e89c55eSLorenzo Pieralisi break; 8845e89c55eSLorenzo Pieralisi #endif 8855e89c55eSLorenzo Pieralisi 88608e875c1SCatalin Marinas default: 88708e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 88808e875c1SCatalin Marinas break; 88908e875c1SCatalin Marinas } 89045ed695aSNicolas Pitre 89145ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) 892be081d9bSStephen Boyd trace_ipi_exit_rcuidle(ipi_types[ipinr]); 89308e875c1SCatalin Marinas set_irq_regs(old_regs); 89408e875c1SCatalin Marinas } 89508e875c1SCatalin Marinas 89608e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 89708e875c1SCatalin Marinas { 89808e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 89908e875c1SCatalin Marinas } 90008e875c1SCatalin Marinas 9011f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 9021f85008eSLorenzo Pieralisi void tick_broadcast(const struct cpumask *mask) 9031f85008eSLorenzo Pieralisi { 9041f85008eSLorenzo Pieralisi smp_cross_call(mask, IPI_TIMER); 9051f85008eSLorenzo Pieralisi } 9061f85008eSLorenzo Pieralisi #endif 9071f85008eSLorenzo Pieralisi 90808e875c1SCatalin Marinas void smp_send_stop(void) 90908e875c1SCatalin Marinas { 91008e875c1SCatalin Marinas unsigned long timeout; 91108e875c1SCatalin Marinas 91208e875c1SCatalin Marinas if (num_online_cpus() > 1) { 91308e875c1SCatalin Marinas cpumask_t mask; 91408e875c1SCatalin Marinas 91508e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 916434ed7f4SRusty Russell cpumask_clear_cpu(smp_processor_id(), &mask); 91708e875c1SCatalin Marinas 91882611c14SJan Glauber if (system_state == SYSTEM_BOOTING || 91982611c14SJan Glauber system_state == SYSTEM_RUNNING) 92082611c14SJan Glauber pr_crit("SMP: stopping secondary CPUs\n"); 92108e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 92208e875c1SCatalin Marinas } 92308e875c1SCatalin Marinas 92408e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 92508e875c1SCatalin Marinas timeout = USEC_PER_SEC; 92608e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 92708e875c1SCatalin Marinas udelay(1); 92808e875c1SCatalin Marinas 92908e875c1SCatalin Marinas if (num_online_cpus() > 1) 93082611c14SJan Glauber pr_warning("SMP: failed to stop secondary CPUs %*pbl\n", 93182611c14SJan Glauber cpumask_pr_args(cpu_online_mask)); 93208e875c1SCatalin Marinas } 93308e875c1SCatalin Marinas 93408e875c1SCatalin Marinas /* 93508e875c1SCatalin Marinas * not supported here 93608e875c1SCatalin Marinas */ 93708e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 93808e875c1SCatalin Marinas { 93908e875c1SCatalin Marinas return -EINVAL; 94008e875c1SCatalin Marinas } 9415c492c3fSJames Morse 9425c492c3fSJames Morse static bool have_cpu_die(void) 9435c492c3fSJames Morse { 9445c492c3fSJames Morse #ifdef CONFIG_HOTPLUG_CPU 9455c492c3fSJames Morse int any_cpu = raw_smp_processor_id(); 9465c492c3fSJames Morse 9475c492c3fSJames Morse if (cpu_ops[any_cpu]->cpu_die) 9485c492c3fSJames Morse return true; 9495c492c3fSJames Morse #endif 9505c492c3fSJames Morse return false; 9515c492c3fSJames Morse } 9525c492c3fSJames Morse 9535c492c3fSJames Morse bool cpus_are_stuck_in_kernel(void) 9545c492c3fSJames Morse { 9555c492c3fSJames Morse bool smp_spin_tables = (num_possible_cpus() > 1 && !have_cpu_die()); 9565c492c3fSJames Morse 9575c492c3fSJames Morse return !!cpus_stuck_in_kernel || smp_spin_tables; 9585c492c3fSJames Morse } 959