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> 2508e875c1SCatalin Marinas #include <linux/interrupt.h> 2608e875c1SCatalin Marinas #include <linux/cache.h> 2708e875c1SCatalin Marinas #include <linux/profile.h> 2808e875c1SCatalin Marinas #include <linux/errno.h> 2908e875c1SCatalin Marinas #include <linux/mm.h> 3008e875c1SCatalin Marinas #include <linux/err.h> 3108e875c1SCatalin Marinas #include <linux/cpu.h> 3208e875c1SCatalin Marinas #include <linux/smp.h> 3308e875c1SCatalin Marinas #include <linux/seq_file.h> 3408e875c1SCatalin Marinas #include <linux/irq.h> 3508e875c1SCatalin Marinas #include <linux/percpu.h> 3608e875c1SCatalin Marinas #include <linux/clockchips.h> 3708e875c1SCatalin Marinas #include <linux/completion.h> 3808e875c1SCatalin Marinas #include <linux/of.h> 39eb631bb5SLarry Bassel #include <linux/irq_work.h> 4008e875c1SCatalin Marinas 41e039ee4eSAndre Przywara #include <asm/alternative.h> 4208e875c1SCatalin Marinas #include <asm/atomic.h> 4308e875c1SCatalin Marinas #include <asm/cacheflush.h> 44df857416SMark Rutland #include <asm/cpu.h> 4508e875c1SCatalin Marinas #include <asm/cputype.h> 46cd1aebf5SMark Rutland #include <asm/cpu_ops.h> 4708e875c1SCatalin Marinas #include <asm/mmu_context.h> 481a2db300SGanapatrao Kulkarni #include <asm/numa.h> 4908e875c1SCatalin Marinas #include <asm/pgtable.h> 5008e875c1SCatalin Marinas #include <asm/pgalloc.h> 5108e875c1SCatalin Marinas #include <asm/processor.h> 524c7aa002SJavi Merino #include <asm/smp_plat.h> 5308e875c1SCatalin Marinas #include <asm/sections.h> 5408e875c1SCatalin Marinas #include <asm/tlbflush.h> 5508e875c1SCatalin Marinas #include <asm/ptrace.h> 56377bcff9SJonas Rabenstein #include <asm/virt.h> 5708e875c1SCatalin Marinas 5845ed695aSNicolas Pitre #define CREATE_TRACE_POINTS 5945ed695aSNicolas Pitre #include <trace/events/ipi.h> 6045ed695aSNicolas Pitre 6108e875c1SCatalin Marinas /* 6208e875c1SCatalin Marinas * as from 2.5, kernels no longer have an init_tasks structure 6308e875c1SCatalin Marinas * so we need some other way of telling a new secondary core 6408e875c1SCatalin Marinas * where to place its SVC stack 6508e875c1SCatalin Marinas */ 6608e875c1SCatalin Marinas struct secondary_data secondary_data; 67bb905274SSuzuki K Poulose /* Number of CPUs which aren't online, but looping in kernel text. */ 68bb905274SSuzuki K Poulose int cpus_stuck_in_kernel; 6908e875c1SCatalin Marinas 7008e875c1SCatalin Marinas enum ipi_msg_type { 7108e875c1SCatalin Marinas IPI_RESCHEDULE, 7208e875c1SCatalin Marinas IPI_CALL_FUNC, 7308e875c1SCatalin Marinas IPI_CPU_STOP, 741f85008eSLorenzo Pieralisi IPI_TIMER, 75eb631bb5SLarry Bassel IPI_IRQ_WORK, 765e89c55eSLorenzo Pieralisi IPI_WAKEUP 7708e875c1SCatalin Marinas }; 7808e875c1SCatalin Marinas 79ac1ad20fSSuzuki K Poulose #ifdef CONFIG_ARM64_VHE 80ac1ad20fSSuzuki K Poulose 81ac1ad20fSSuzuki K Poulose /* Whether the boot CPU is running in HYP mode or not*/ 82ac1ad20fSSuzuki K Poulose static bool boot_cpu_hyp_mode; 83ac1ad20fSSuzuki K Poulose 84ac1ad20fSSuzuki K Poulose static inline void save_boot_cpu_run_el(void) 85ac1ad20fSSuzuki K Poulose { 86ac1ad20fSSuzuki K Poulose boot_cpu_hyp_mode = is_kernel_in_hyp_mode(); 87ac1ad20fSSuzuki K Poulose } 88ac1ad20fSSuzuki K Poulose 89ac1ad20fSSuzuki K Poulose static inline bool is_boot_cpu_in_hyp_mode(void) 90ac1ad20fSSuzuki K Poulose { 91ac1ad20fSSuzuki K Poulose return boot_cpu_hyp_mode; 92ac1ad20fSSuzuki K Poulose } 93ac1ad20fSSuzuki K Poulose 94ac1ad20fSSuzuki K Poulose /* 95ac1ad20fSSuzuki K Poulose * Verify that a secondary CPU is running the kernel at the same 96ac1ad20fSSuzuki K Poulose * EL as that of the boot CPU. 97ac1ad20fSSuzuki K Poulose */ 98ac1ad20fSSuzuki K Poulose void verify_cpu_run_el(void) 99ac1ad20fSSuzuki K Poulose { 100ac1ad20fSSuzuki K Poulose bool in_el2 = is_kernel_in_hyp_mode(); 101ac1ad20fSSuzuki K Poulose bool boot_cpu_el2 = is_boot_cpu_in_hyp_mode(); 102ac1ad20fSSuzuki K Poulose 103ac1ad20fSSuzuki K Poulose if (in_el2 ^ boot_cpu_el2) { 104ac1ad20fSSuzuki K Poulose pr_crit("CPU%d: mismatched Exception Level(EL%d) with boot CPU(EL%d)\n", 105ac1ad20fSSuzuki K Poulose smp_processor_id(), 106ac1ad20fSSuzuki K Poulose in_el2 ? 2 : 1, 107ac1ad20fSSuzuki K Poulose boot_cpu_el2 ? 2 : 1); 108ac1ad20fSSuzuki K Poulose cpu_panic_kernel(); 109ac1ad20fSSuzuki K Poulose } 110ac1ad20fSSuzuki K Poulose } 111ac1ad20fSSuzuki K Poulose 112ac1ad20fSSuzuki K Poulose #else 113ac1ad20fSSuzuki K Poulose static inline void save_boot_cpu_run_el(void) {} 114ac1ad20fSSuzuki K Poulose #endif 115ac1ad20fSSuzuki K Poulose 116bb905274SSuzuki K Poulose #ifdef CONFIG_HOTPLUG_CPU 117bb905274SSuzuki K Poulose static int op_cpu_kill(unsigned int cpu); 118bb905274SSuzuki K Poulose #else 119bb905274SSuzuki K Poulose static inline int op_cpu_kill(unsigned int cpu) 120bb905274SSuzuki K Poulose { 121bb905274SSuzuki K Poulose return -ENOSYS; 122bb905274SSuzuki K Poulose } 123bb905274SSuzuki K Poulose #endif 124bb905274SSuzuki K Poulose 125bb905274SSuzuki K Poulose 12608e875c1SCatalin Marinas /* 12708e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 12808e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 12908e875c1SCatalin Marinas */ 130b8c6453aSPaul Gortmaker static int boot_secondary(unsigned int cpu, struct task_struct *idle) 13108e875c1SCatalin Marinas { 132652af899SMark Rutland if (cpu_ops[cpu]->cpu_boot) 133652af899SMark Rutland return cpu_ops[cpu]->cpu_boot(cpu); 13408e875c1SCatalin Marinas 135652af899SMark Rutland return -EOPNOTSUPP; 13608e875c1SCatalin Marinas } 13708e875c1SCatalin Marinas 13808e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 13908e875c1SCatalin Marinas 140b8c6453aSPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *idle) 14108e875c1SCatalin Marinas { 14208e875c1SCatalin Marinas int ret; 143bb905274SSuzuki K Poulose long status; 14408e875c1SCatalin Marinas 14508e875c1SCatalin Marinas /* 14608e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 14708e875c1SCatalin Marinas * page tables. 14808e875c1SCatalin Marinas */ 14908e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 150bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_MMU_OFF); 15108e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 15208e875c1SCatalin Marinas 15308e875c1SCatalin Marinas /* 15408e875c1SCatalin Marinas * Now bring the CPU into our world. 15508e875c1SCatalin Marinas */ 15608e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 15708e875c1SCatalin Marinas if (ret == 0) { 15808e875c1SCatalin Marinas /* 15908e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 16008e875c1SCatalin Marinas * time out. 16108e875c1SCatalin Marinas */ 16208e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 16308e875c1SCatalin Marinas msecs_to_jiffies(1000)); 16408e875c1SCatalin Marinas 16508e875c1SCatalin Marinas if (!cpu_online(cpu)) { 16608e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 16708e875c1SCatalin Marinas ret = -EIO; 16808e875c1SCatalin Marinas } 16908e875c1SCatalin Marinas } else { 17008e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 17108e875c1SCatalin Marinas } 17208e875c1SCatalin Marinas 17308e875c1SCatalin Marinas secondary_data.stack = NULL; 174bb905274SSuzuki K Poulose status = READ_ONCE(secondary_data.status); 175bb905274SSuzuki K Poulose if (ret && status) { 176bb905274SSuzuki K Poulose 177bb905274SSuzuki K Poulose if (status == CPU_MMU_OFF) 178bb905274SSuzuki K Poulose status = READ_ONCE(__early_cpu_boot_status); 179bb905274SSuzuki K Poulose 180bb905274SSuzuki K Poulose switch (status) { 181bb905274SSuzuki K Poulose default: 182bb905274SSuzuki K Poulose pr_err("CPU%u: failed in unknown state : 0x%lx\n", 183bb905274SSuzuki K Poulose cpu, status); 184bb905274SSuzuki K Poulose break; 185bb905274SSuzuki K Poulose case CPU_KILL_ME: 186bb905274SSuzuki K Poulose if (!op_cpu_kill(cpu)) { 187bb905274SSuzuki K Poulose pr_crit("CPU%u: died during early boot\n", cpu); 188bb905274SSuzuki K Poulose break; 189bb905274SSuzuki K Poulose } 190bb905274SSuzuki K Poulose /* Fall through */ 191bb905274SSuzuki K Poulose pr_crit("CPU%u: may not have shut down cleanly\n", cpu); 192bb905274SSuzuki K Poulose case CPU_STUCK_IN_KERNEL: 193bb905274SSuzuki K Poulose pr_crit("CPU%u: is stuck in kernel\n", cpu); 194bb905274SSuzuki K Poulose cpus_stuck_in_kernel++; 195bb905274SSuzuki K Poulose break; 196bb905274SSuzuki K Poulose case CPU_PANIC_KERNEL: 197bb905274SSuzuki K Poulose panic("CPU%u detected unsupported configuration\n", cpu); 198bb905274SSuzuki K Poulose } 199bb905274SSuzuki K Poulose } 20008e875c1SCatalin Marinas 20108e875c1SCatalin Marinas return ret; 20208e875c1SCatalin Marinas } 20308e875c1SCatalin Marinas 204f6e763b9SMark Brown static void smp_store_cpu_info(unsigned int cpuid) 205f6e763b9SMark Brown { 206f6e763b9SMark Brown store_cpu_topology(cpuid); 2071a2db300SGanapatrao Kulkarni numa_store_cpu_info(cpuid); 208f6e763b9SMark Brown } 209f6e763b9SMark Brown 21008e875c1SCatalin Marinas /* 21108e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 21208e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 21308e875c1SCatalin Marinas */ 214b8c6453aSPaul Gortmaker asmlinkage void secondary_start_kernel(void) 21508e875c1SCatalin Marinas { 21608e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 21708e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 21808e875c1SCatalin Marinas 21908e875c1SCatalin Marinas /* 22008e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 22108e875c1SCatalin Marinas * reference and switch to it. 22208e875c1SCatalin Marinas */ 22308e875c1SCatalin Marinas atomic_inc(&mm->mm_count); 22408e875c1SCatalin Marinas current->active_mm = mm; 22508e875c1SCatalin Marinas 22671586276SWill Deacon set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 22771586276SWill Deacon 22808e875c1SCatalin Marinas /* 22908e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 23008e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 23108e875c1SCatalin Marinas */ 2329e8e865bSMark Rutland cpu_uninstall_idmap(); 23308e875c1SCatalin Marinas 23408e875c1SCatalin Marinas preempt_disable(); 23508e875c1SCatalin Marinas trace_hardirqs_off(); 23608e875c1SCatalin Marinas 237dbb4e152SSuzuki K. Poulose /* 238dbb4e152SSuzuki K. Poulose * If the system has established the capabilities, make sure 239dbb4e152SSuzuki K. Poulose * this CPU ticks all of those. If it doesn't, the CPU will 240dbb4e152SSuzuki K. Poulose * fail to come online. 241dbb4e152SSuzuki K. Poulose */ 242dbb4e152SSuzuki K. Poulose verify_local_cpu_capabilities(); 243dbb4e152SSuzuki K. Poulose 244652af899SMark Rutland if (cpu_ops[cpu]->cpu_postboot) 245652af899SMark Rutland cpu_ops[cpu]->cpu_postboot(); 24608e875c1SCatalin Marinas 24708e875c1SCatalin Marinas /* 248df857416SMark Rutland * Log the CPU info before it is marked online and might get read. 249df857416SMark Rutland */ 250df857416SMark Rutland cpuinfo_store_cpu(); 251df857416SMark Rutland 252df857416SMark Rutland /* 2537ade67b5SMarc Zyngier * Enable GIC and timers. 2547ade67b5SMarc Zyngier */ 2557ade67b5SMarc Zyngier notify_cpu_starting(cpu); 2567ade67b5SMarc Zyngier 257f6e763b9SMark Brown smp_store_cpu_info(cpu); 258f6e763b9SMark Brown 2597ade67b5SMarc Zyngier /* 26008e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 26108e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 26208e875c1SCatalin Marinas * before we continue. 26308e875c1SCatalin Marinas */ 26464f17818SSuzuki K. Poulose pr_info("CPU%u: Booted secondary processor [%08x]\n", 26564f17818SSuzuki K. Poulose cpu, read_cpuid_id()); 266bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_BOOT_SUCCESS); 26708e875c1SCatalin Marinas set_cpu_online(cpu, true); 268b3770b32SWill Deacon complete(&cpu_running); 26908e875c1SCatalin Marinas 27053ae3acdSCatalin Marinas local_irq_enable(); 271b3bf6aa7SCatalin Marinas local_async_enable(); 27253ae3acdSCatalin Marinas 27353ae3acdSCatalin Marinas /* 27408e875c1SCatalin Marinas * OK, it's off to the idle thread for us 27508e875c1SCatalin Marinas */ 276fc6d73d6SThomas Gleixner cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 27708e875c1SCatalin Marinas } 27808e875c1SCatalin Marinas 2799327e2c6SMark Rutland #ifdef CONFIG_HOTPLUG_CPU 2809327e2c6SMark Rutland static int op_cpu_disable(unsigned int cpu) 2819327e2c6SMark Rutland { 2829327e2c6SMark Rutland /* 2839327e2c6SMark Rutland * If we don't have a cpu_die method, abort before we reach the point 2849327e2c6SMark Rutland * of no return. CPU0 may not have an cpu_ops, so test for it. 2859327e2c6SMark Rutland */ 2869327e2c6SMark Rutland if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) 2879327e2c6SMark Rutland return -EOPNOTSUPP; 2889327e2c6SMark Rutland 2899327e2c6SMark Rutland /* 2909327e2c6SMark Rutland * We may need to abort a hot unplug for some other mechanism-specific 2919327e2c6SMark Rutland * reason. 2929327e2c6SMark Rutland */ 2939327e2c6SMark Rutland if (cpu_ops[cpu]->cpu_disable) 2949327e2c6SMark Rutland return cpu_ops[cpu]->cpu_disable(cpu); 2959327e2c6SMark Rutland 2969327e2c6SMark Rutland return 0; 2979327e2c6SMark Rutland } 2989327e2c6SMark Rutland 2999327e2c6SMark Rutland /* 3009327e2c6SMark Rutland * __cpu_disable runs on the processor to be shutdown. 3019327e2c6SMark Rutland */ 3029327e2c6SMark Rutland int __cpu_disable(void) 3039327e2c6SMark Rutland { 3049327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 3059327e2c6SMark Rutland int ret; 3069327e2c6SMark Rutland 3079327e2c6SMark Rutland ret = op_cpu_disable(cpu); 3089327e2c6SMark Rutland if (ret) 3099327e2c6SMark Rutland return ret; 3109327e2c6SMark Rutland 3119327e2c6SMark Rutland /* 3129327e2c6SMark Rutland * Take this CPU offline. Once we clear this, we can't return, 3139327e2c6SMark Rutland * and we must not schedule until we're ready to give up the cpu. 3149327e2c6SMark Rutland */ 3159327e2c6SMark Rutland set_cpu_online(cpu, false); 3169327e2c6SMark Rutland 3179327e2c6SMark Rutland /* 3189327e2c6SMark Rutland * OK - migrate IRQs away from this CPU 3199327e2c6SMark Rutland */ 320217d453dSYang Yingliang irq_migrate_all_off_this_cpu(); 321217d453dSYang Yingliang 3229327e2c6SMark Rutland return 0; 3239327e2c6SMark Rutland } 3249327e2c6SMark Rutland 325c814ca02SAshwin Chaugule static int op_cpu_kill(unsigned int cpu) 326c814ca02SAshwin Chaugule { 327c814ca02SAshwin Chaugule /* 328c814ca02SAshwin Chaugule * If we have no means of synchronising with the dying CPU, then assume 329c814ca02SAshwin Chaugule * that it is really dead. We can only wait for an arbitrary length of 330c814ca02SAshwin Chaugule * time and hope that it's dead, so let's skip the wait and just hope. 331c814ca02SAshwin Chaugule */ 332c814ca02SAshwin Chaugule if (!cpu_ops[cpu]->cpu_kill) 3336b99c68cSMark Rutland return 0; 334c814ca02SAshwin Chaugule 335c814ca02SAshwin Chaugule return cpu_ops[cpu]->cpu_kill(cpu); 336c814ca02SAshwin Chaugule } 337c814ca02SAshwin Chaugule 3389327e2c6SMark Rutland /* 3399327e2c6SMark Rutland * called on the thread which is asking for a CPU to be shutdown - 3409327e2c6SMark Rutland * waits until shutdown has completed, or it is timed out. 3419327e2c6SMark Rutland */ 3429327e2c6SMark Rutland void __cpu_die(unsigned int cpu) 3439327e2c6SMark Rutland { 3446b99c68cSMark Rutland int err; 3456b99c68cSMark Rutland 34605981277SPaul E. McKenney if (!cpu_wait_death(cpu, 5)) { 3479327e2c6SMark Rutland pr_crit("CPU%u: cpu didn't die\n", cpu); 3489327e2c6SMark Rutland return; 3499327e2c6SMark Rutland } 3509327e2c6SMark Rutland pr_notice("CPU%u: shutdown\n", cpu); 351c814ca02SAshwin Chaugule 352c814ca02SAshwin Chaugule /* 353c814ca02SAshwin Chaugule * Now that the dying CPU is beyond the point of no return w.r.t. 354c814ca02SAshwin Chaugule * in-kernel synchronisation, try to get the firwmare to help us to 355c814ca02SAshwin Chaugule * verify that it has really left the kernel before we consider 356c814ca02SAshwin Chaugule * clobbering anything it might still be using. 357c814ca02SAshwin Chaugule */ 3586b99c68cSMark Rutland err = op_cpu_kill(cpu); 3596b99c68cSMark Rutland if (err) 3606b99c68cSMark Rutland pr_warn("CPU%d may not have shut down cleanly: %d\n", 3616b99c68cSMark Rutland cpu, err); 3629327e2c6SMark Rutland } 3639327e2c6SMark Rutland 3649327e2c6SMark Rutland /* 3659327e2c6SMark Rutland * Called from the idle thread for the CPU which has been shutdown. 3669327e2c6SMark Rutland * 3679327e2c6SMark Rutland * Note that we disable IRQs here, but do not re-enable them 3689327e2c6SMark Rutland * before returning to the caller. This is also the behaviour 3699327e2c6SMark Rutland * of the other hotplug-cpu capable cores, so presumably coming 3709327e2c6SMark Rutland * out of idle fixes this. 3719327e2c6SMark Rutland */ 3729327e2c6SMark Rutland void cpu_die(void) 3739327e2c6SMark Rutland { 3749327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 3759327e2c6SMark Rutland 3769327e2c6SMark Rutland idle_task_exit(); 3779327e2c6SMark Rutland 3789327e2c6SMark Rutland local_irq_disable(); 3799327e2c6SMark Rutland 3809327e2c6SMark Rutland /* Tell __cpu_die() that this CPU is now safe to dispose of */ 38105981277SPaul E. McKenney (void)cpu_report_death(); 3829327e2c6SMark Rutland 3839327e2c6SMark Rutland /* 3849327e2c6SMark Rutland * Actually shutdown the CPU. This must never fail. The specific hotplug 3859327e2c6SMark Rutland * mechanism must perform all required cache maintenance to ensure that 3869327e2c6SMark Rutland * no dirty lines are lost in the process of shutting down the CPU. 3879327e2c6SMark Rutland */ 3889327e2c6SMark Rutland cpu_ops[cpu]->cpu_die(cpu); 3899327e2c6SMark Rutland 3909327e2c6SMark Rutland BUG(); 3919327e2c6SMark Rutland } 3929327e2c6SMark Rutland #endif 3939327e2c6SMark Rutland 394fce6361fSSuzuki K Poulose /* 395fce6361fSSuzuki K Poulose * Kill the calling secondary CPU, early in bringup before it is turned 396fce6361fSSuzuki K Poulose * online. 397fce6361fSSuzuki K Poulose */ 398fce6361fSSuzuki K Poulose void cpu_die_early(void) 399fce6361fSSuzuki K Poulose { 400fce6361fSSuzuki K Poulose int cpu = smp_processor_id(); 401fce6361fSSuzuki K Poulose 402fce6361fSSuzuki K Poulose pr_crit("CPU%d: will not boot\n", cpu); 403fce6361fSSuzuki K Poulose 404fce6361fSSuzuki K Poulose /* Mark this CPU absent */ 405fce6361fSSuzuki K Poulose set_cpu_present(cpu, 0); 406fce6361fSSuzuki K Poulose 407fce6361fSSuzuki K Poulose #ifdef CONFIG_HOTPLUG_CPU 408bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_KILL_ME); 409fce6361fSSuzuki K Poulose /* Check if we can park ourselves */ 410fce6361fSSuzuki K Poulose if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_die) 411fce6361fSSuzuki K Poulose cpu_ops[cpu]->cpu_die(cpu); 412fce6361fSSuzuki K Poulose #endif 413bb905274SSuzuki K Poulose update_cpu_boot_status(CPU_STUCK_IN_KERNEL); 414fce6361fSSuzuki K Poulose 415fce6361fSSuzuki K Poulose cpu_park_loop(); 416fce6361fSSuzuki K Poulose } 417fce6361fSSuzuki K Poulose 418377bcff9SJonas Rabenstein static void __init hyp_mode_check(void) 419377bcff9SJonas Rabenstein { 420377bcff9SJonas Rabenstein if (is_hyp_mode_available()) 421377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL2\n"); 422377bcff9SJonas Rabenstein else if (is_hyp_mode_mismatched()) 423377bcff9SJonas Rabenstein WARN_TAINT(1, TAINT_CPU_OUT_OF_SPEC, 424377bcff9SJonas Rabenstein "CPU: CPUs started in inconsistent modes"); 425377bcff9SJonas Rabenstein else 426377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL1\n"); 427377bcff9SJonas Rabenstein } 428377bcff9SJonas Rabenstein 42908e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 43008e875c1SCatalin Marinas { 431326b16dbSWill Deacon pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); 4323a75578eSSuzuki K. Poulose setup_cpu_features(); 433377bcff9SJonas Rabenstein hyp_mode_check(); 434377bcff9SJonas Rabenstein apply_alternatives_all(); 43508e875c1SCatalin Marinas } 43608e875c1SCatalin Marinas 43708e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 43808e875c1SCatalin Marinas { 4399113c2aaSSuzuki K Poulose set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 440efd9e03fSCatalin Marinas /* 441efd9e03fSCatalin Marinas * Initialise the static keys early as they may be enabled by the 442efd9e03fSCatalin Marinas * cpufeature code. 443efd9e03fSCatalin Marinas */ 444efd9e03fSCatalin Marinas jump_label_init(); 4454b998ff1SSuzuki K. Poulose cpuinfo_store_boot_cpu(); 446ac1ad20fSSuzuki K Poulose save_boot_cpu_run_el(); 44708e875c1SCatalin Marinas } 44808e875c1SCatalin Marinas 4490f078336SLorenzo Pieralisi static u64 __init of_get_cpu_mpidr(struct device_node *dn) 4500f078336SLorenzo Pieralisi { 4510f078336SLorenzo Pieralisi const __be32 *cell; 4520f078336SLorenzo Pieralisi u64 hwid; 4530f078336SLorenzo Pieralisi 4540f078336SLorenzo Pieralisi /* 4550f078336SLorenzo Pieralisi * A cpu node with missing "reg" property is 4560f078336SLorenzo Pieralisi * considered invalid to build a cpu_logical_map 4570f078336SLorenzo Pieralisi * entry. 4580f078336SLorenzo Pieralisi */ 4590f078336SLorenzo Pieralisi cell = of_get_property(dn, "reg", NULL); 4600f078336SLorenzo Pieralisi if (!cell) { 4610f078336SLorenzo Pieralisi pr_err("%s: missing reg property\n", dn->full_name); 4620f078336SLorenzo Pieralisi return INVALID_HWID; 4630f078336SLorenzo Pieralisi } 4640f078336SLorenzo Pieralisi 4650f078336SLorenzo Pieralisi hwid = of_read_number(cell, of_n_addr_cells(dn)); 4660f078336SLorenzo Pieralisi /* 4670f078336SLorenzo Pieralisi * Non affinity bits must be set to 0 in the DT 4680f078336SLorenzo Pieralisi */ 4690f078336SLorenzo Pieralisi if (hwid & ~MPIDR_HWID_BITMASK) { 4700f078336SLorenzo Pieralisi pr_err("%s: invalid reg property\n", dn->full_name); 4710f078336SLorenzo Pieralisi return INVALID_HWID; 4720f078336SLorenzo Pieralisi } 4730f078336SLorenzo Pieralisi return hwid; 4740f078336SLorenzo Pieralisi } 4750f078336SLorenzo Pieralisi 4760f078336SLorenzo Pieralisi /* 4770f078336SLorenzo Pieralisi * Duplicate MPIDRs are a recipe for disaster. Scan all initialized 4780f078336SLorenzo Pieralisi * entries and check for duplicates. If any is found just ignore the 4790f078336SLorenzo Pieralisi * cpu. cpu_logical_map was initialized to INVALID_HWID to avoid 4800f078336SLorenzo Pieralisi * matching valid MPIDR values. 4810f078336SLorenzo Pieralisi */ 4820f078336SLorenzo Pieralisi static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid) 4830f078336SLorenzo Pieralisi { 4840f078336SLorenzo Pieralisi unsigned int i; 4850f078336SLorenzo Pieralisi 4860f078336SLorenzo Pieralisi for (i = 1; (i < cpu) && (i < NR_CPUS); i++) 4870f078336SLorenzo Pieralisi if (cpu_logical_map(i) == hwid) 4880f078336SLorenzo Pieralisi return true; 4890f078336SLorenzo Pieralisi return false; 4900f078336SLorenzo Pieralisi } 4910f078336SLorenzo Pieralisi 49208e875c1SCatalin Marinas /* 493819a8826SLorenzo Pieralisi * Initialize cpu operations for a logical cpu and 494819a8826SLorenzo Pieralisi * set it in the possible mask on success 495819a8826SLorenzo Pieralisi */ 496819a8826SLorenzo Pieralisi static int __init smp_cpu_setup(int cpu) 497819a8826SLorenzo Pieralisi { 498819a8826SLorenzo Pieralisi if (cpu_read_ops(cpu)) 499819a8826SLorenzo Pieralisi return -ENODEV; 500819a8826SLorenzo Pieralisi 501819a8826SLorenzo Pieralisi if (cpu_ops[cpu]->cpu_init(cpu)) 502819a8826SLorenzo Pieralisi return -ENODEV; 503819a8826SLorenzo Pieralisi 504819a8826SLorenzo Pieralisi set_cpu_possible(cpu, true); 505819a8826SLorenzo Pieralisi 506819a8826SLorenzo Pieralisi return 0; 507819a8826SLorenzo Pieralisi } 508819a8826SLorenzo Pieralisi 5090f078336SLorenzo Pieralisi static bool bootcpu_valid __initdata; 5100f078336SLorenzo Pieralisi static unsigned int cpu_count = 1; 5110f078336SLorenzo Pieralisi 5120f078336SLorenzo Pieralisi #ifdef CONFIG_ACPI 5130f078336SLorenzo Pieralisi /* 5140f078336SLorenzo Pieralisi * acpi_map_gic_cpu_interface - parse processor MADT entry 5150f078336SLorenzo Pieralisi * 5160f078336SLorenzo Pieralisi * Carry out sanity checks on MADT processor entry and initialize 5170f078336SLorenzo Pieralisi * cpu_logical_map on success 5180f078336SLorenzo Pieralisi */ 5190f078336SLorenzo Pieralisi static void __init 5200f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) 5210f078336SLorenzo Pieralisi { 5220f078336SLorenzo Pieralisi u64 hwid = processor->arm_mpidr; 5230f078336SLorenzo Pieralisi 524f9058929SHanjun Guo if (!(processor->flags & ACPI_MADT_ENABLED)) { 525f9058929SHanjun Guo pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid); 5260f078336SLorenzo Pieralisi return; 5270f078336SLorenzo Pieralisi } 5280f078336SLorenzo Pieralisi 529f9058929SHanjun Guo if (hwid & ~MPIDR_HWID_BITMASK || hwid == INVALID_HWID) { 530f9058929SHanjun Guo pr_err("skipping CPU entry with invalid MPIDR 0x%llx\n", hwid); 5310f078336SLorenzo Pieralisi return; 5320f078336SLorenzo Pieralisi } 5330f078336SLorenzo Pieralisi 5340f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 5350f078336SLorenzo Pieralisi pr_err("duplicate CPU MPIDR 0x%llx in MADT\n", hwid); 5360f078336SLorenzo Pieralisi return; 5370f078336SLorenzo Pieralisi } 5380f078336SLorenzo Pieralisi 5390f078336SLorenzo Pieralisi /* Check if GICC structure of boot CPU is available in the MADT */ 5400f078336SLorenzo Pieralisi if (cpu_logical_map(0) == hwid) { 5410f078336SLorenzo Pieralisi if (bootcpu_valid) { 5420f078336SLorenzo Pieralisi pr_err("duplicate boot CPU MPIDR: 0x%llx in MADT\n", 5430f078336SLorenzo Pieralisi hwid); 5440f078336SLorenzo Pieralisi return; 5450f078336SLorenzo Pieralisi } 5460f078336SLorenzo Pieralisi bootcpu_valid = true; 5470f078336SLorenzo Pieralisi return; 5480f078336SLorenzo Pieralisi } 5490f078336SLorenzo Pieralisi 5500f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 5510f078336SLorenzo Pieralisi return; 5520f078336SLorenzo Pieralisi 5530f078336SLorenzo Pieralisi /* map the logical cpu id to cpu MPIDR */ 5540f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 5550f078336SLorenzo Pieralisi 5565e89c55eSLorenzo Pieralisi /* 5575e89c55eSLorenzo Pieralisi * Set-up the ACPI parking protocol cpu entries 5585e89c55eSLorenzo Pieralisi * while initializing the cpu_logical_map to 5595e89c55eSLorenzo Pieralisi * avoid parsing MADT entries multiple times for 5605e89c55eSLorenzo Pieralisi * nothing (ie a valid cpu_logical_map entry should 5615e89c55eSLorenzo Pieralisi * contain a valid parking protocol data set to 5625e89c55eSLorenzo Pieralisi * initialize the cpu if the parking protocol is 5635e89c55eSLorenzo Pieralisi * the only available enable method). 5645e89c55eSLorenzo Pieralisi */ 5655e89c55eSLorenzo Pieralisi acpi_set_mailbox_entry(cpu_count, processor); 5665e89c55eSLorenzo Pieralisi 567d8b47fcaSHanjun Guo early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid)); 568d8b47fcaSHanjun Guo 5690f078336SLorenzo Pieralisi cpu_count++; 5700f078336SLorenzo Pieralisi } 5710f078336SLorenzo Pieralisi 5720f078336SLorenzo Pieralisi static int __init 5730f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, 5740f078336SLorenzo Pieralisi const unsigned long end) 5750f078336SLorenzo Pieralisi { 5760f078336SLorenzo Pieralisi struct acpi_madt_generic_interrupt *processor; 5770f078336SLorenzo Pieralisi 5780f078336SLorenzo Pieralisi processor = (struct acpi_madt_generic_interrupt *)header; 57999e3e3aeSAl Stone if (BAD_MADT_GICC_ENTRY(processor, end)) 5800f078336SLorenzo Pieralisi return -EINVAL; 5810f078336SLorenzo Pieralisi 5820f078336SLorenzo Pieralisi acpi_table_print_madt_entry(header); 5830f078336SLorenzo Pieralisi 5840f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(processor); 5850f078336SLorenzo Pieralisi 5860f078336SLorenzo Pieralisi return 0; 5870f078336SLorenzo Pieralisi } 5880f078336SLorenzo Pieralisi #else 5890f078336SLorenzo Pieralisi #define acpi_table_parse_madt(...) do { } while (0) 5900f078336SLorenzo Pieralisi #endif 5910f078336SLorenzo Pieralisi 592819a8826SLorenzo Pieralisi /* 5934c7aa002SJavi Merino * Enumerate the possible CPU set from the device tree and build the 5944c7aa002SJavi Merino * cpu logical map array containing MPIDR values related to logical 5954c7aa002SJavi Merino * cpus. Assumes that cpu_logical_map(0) has already been initialized. 59608e875c1SCatalin Marinas */ 59729b8302bSJisheng Zhang static void __init of_parse_and_init_cpus(void) 59808e875c1SCatalin Marinas { 59908e875c1SCatalin Marinas struct device_node *dn = NULL; 60008e875c1SCatalin Marinas 60108e875c1SCatalin Marinas while ((dn = of_find_node_by_type(dn, "cpu"))) { 6020f078336SLorenzo Pieralisi u64 hwid = of_get_cpu_mpidr(dn); 6034c7aa002SJavi Merino 6040f078336SLorenzo Pieralisi if (hwid == INVALID_HWID) 6054c7aa002SJavi Merino goto next; 6064c7aa002SJavi Merino 6070f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 6084c7aa002SJavi Merino pr_err("%s: duplicate cpu reg properties in the DT\n", 6094c7aa002SJavi Merino dn->full_name); 6104c7aa002SJavi Merino goto next; 6114c7aa002SJavi Merino } 6124c7aa002SJavi Merino 6134c7aa002SJavi Merino /* 6144c7aa002SJavi Merino * The numbering scheme requires that the boot CPU 6154c7aa002SJavi Merino * must be assigned logical id 0. Record it so that 6164c7aa002SJavi Merino * the logical map built from DT is validated and can 6174c7aa002SJavi Merino * be used. 6184c7aa002SJavi Merino */ 6194c7aa002SJavi Merino if (hwid == cpu_logical_map(0)) { 6204c7aa002SJavi Merino if (bootcpu_valid) { 6214c7aa002SJavi Merino pr_err("%s: duplicate boot cpu reg property in DT\n", 6224c7aa002SJavi Merino dn->full_name); 6234c7aa002SJavi Merino goto next; 6244c7aa002SJavi Merino } 6254c7aa002SJavi Merino 6264c7aa002SJavi Merino bootcpu_valid = true; 627*7ba5f605SZhen Lei early_map_cpu_to_node(0, of_node_to_nid(dn)); 6284c7aa002SJavi Merino 6294c7aa002SJavi Merino /* 6304c7aa002SJavi Merino * cpu_logical_map has already been 6314c7aa002SJavi Merino * initialized and the boot cpu doesn't need 6324c7aa002SJavi Merino * the enable-method so continue without 6334c7aa002SJavi Merino * incrementing cpu. 6344c7aa002SJavi Merino */ 6354c7aa002SJavi Merino continue; 6364c7aa002SJavi Merino } 6374c7aa002SJavi Merino 6380f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 63908e875c1SCatalin Marinas goto next; 64008e875c1SCatalin Marinas 6414c7aa002SJavi Merino pr_debug("cpu logical map 0x%llx\n", hwid); 6420f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 6431a2db300SGanapatrao Kulkarni 6441a2db300SGanapatrao Kulkarni early_map_cpu_to_node(cpu_count, of_node_to_nid(dn)); 64508e875c1SCatalin Marinas next: 6460f078336SLorenzo Pieralisi cpu_count++; 6470f078336SLorenzo Pieralisi } 64808e875c1SCatalin Marinas } 64908e875c1SCatalin Marinas 6500f078336SLorenzo Pieralisi /* 6510f078336SLorenzo Pieralisi * Enumerate the possible CPU set from the device tree or ACPI and build the 6520f078336SLorenzo Pieralisi * cpu logical map array containing MPIDR values related to logical 6530f078336SLorenzo Pieralisi * cpus. Assumes that cpu_logical_map(0) has already been initialized. 6540f078336SLorenzo Pieralisi */ 6550f078336SLorenzo Pieralisi void __init smp_init_cpus(void) 6560f078336SLorenzo Pieralisi { 6570f078336SLorenzo Pieralisi int i; 6580f078336SLorenzo Pieralisi 6590f078336SLorenzo Pieralisi if (acpi_disabled) 6600f078336SLorenzo Pieralisi of_parse_and_init_cpus(); 6610f078336SLorenzo Pieralisi else 6620f078336SLorenzo Pieralisi /* 6630f078336SLorenzo Pieralisi * do a walk of MADT to determine how many CPUs 6640f078336SLorenzo Pieralisi * we have including disabled CPUs, and get information 6650f078336SLorenzo Pieralisi * we need for SMP init 6660f078336SLorenzo Pieralisi */ 6670f078336SLorenzo Pieralisi acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, 6680f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface, 0); 6690f078336SLorenzo Pieralisi 67050ee91bdSKefeng Wang if (cpu_count > nr_cpu_ids) 67150ee91bdSKefeng Wang pr_warn("Number of cores (%d) exceeds configured maximum of %d - clipping\n", 67250ee91bdSKefeng Wang cpu_count, nr_cpu_ids); 6734c7aa002SJavi Merino 6744c7aa002SJavi Merino if (!bootcpu_valid) { 6750f078336SLorenzo Pieralisi pr_err("missing boot CPU MPIDR, not enabling secondaries\n"); 6764c7aa002SJavi Merino return; 6774c7aa002SJavi Merino } 6784c7aa002SJavi Merino 6794c7aa002SJavi Merino /* 680819a8826SLorenzo Pieralisi * We need to set the cpu_logical_map entries before enabling 681819a8826SLorenzo Pieralisi * the cpus so that cpu processor description entries (DT cpu nodes 682819a8826SLorenzo Pieralisi * and ACPI MADT entries) can be retrieved by matching the cpu hwid 683819a8826SLorenzo Pieralisi * with entries in cpu_logical_map while initializing the cpus. 684819a8826SLorenzo Pieralisi * If the cpu set-up fails, invalidate the cpu_logical_map entry. 6854c7aa002SJavi Merino */ 68650ee91bdSKefeng Wang for (i = 1; i < nr_cpu_ids; i++) { 687819a8826SLorenzo Pieralisi if (cpu_logical_map(i) != INVALID_HWID) { 688819a8826SLorenzo Pieralisi if (smp_cpu_setup(i)) 689819a8826SLorenzo Pieralisi cpu_logical_map(i) = INVALID_HWID; 690819a8826SLorenzo Pieralisi } 691819a8826SLorenzo Pieralisi } 69208e875c1SCatalin Marinas } 69308e875c1SCatalin Marinas 69408e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 69508e875c1SCatalin Marinas { 696cd1aebf5SMark Rutland int err; 69744dbcc93SSuzuki K Poulose unsigned int cpu; 69808e875c1SCatalin Marinas 699f6e763b9SMark Brown init_cpu_topology(); 700f6e763b9SMark Brown 701f6e763b9SMark Brown smp_store_cpu_info(smp_processor_id()); 702f6e763b9SMark Brown 70308e875c1SCatalin Marinas /* 704e75118a7SSuzuki K Poulose * If UP is mandated by "nosmp" (which implies "maxcpus=0"), don't set 705e75118a7SSuzuki K Poulose * secondary CPUs present. 706e75118a7SSuzuki K Poulose */ 707e75118a7SSuzuki K Poulose if (max_cpus == 0) 708e75118a7SSuzuki K Poulose return; 709e75118a7SSuzuki K Poulose 710e75118a7SSuzuki K Poulose /* 71108e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 71208e875c1SCatalin Marinas * actually populated at the present time) and release the 71308e875c1SCatalin Marinas * secondaries from the bootloader. 71408e875c1SCatalin Marinas */ 71508e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 71608e875c1SCatalin Marinas 717d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 71808e875c1SCatalin Marinas continue; 71908e875c1SCatalin Marinas 720cd1aebf5SMark Rutland if (!cpu_ops[cpu]) 721d329de3fSMarc Zyngier continue; 722d329de3fSMarc Zyngier 723cd1aebf5SMark Rutland err = cpu_ops[cpu]->cpu_prepare(cpu); 724d329de3fSMarc Zyngier if (err) 725d329de3fSMarc Zyngier continue; 72608e875c1SCatalin Marinas 72708e875c1SCatalin Marinas set_cpu_present(cpu, true); 72808e875c1SCatalin Marinas } 72908e875c1SCatalin Marinas } 73008e875c1SCatalin Marinas 73136310736SFrederic Weisbecker void (*__smp_cross_call)(const struct cpumask *, unsigned int); 73208e875c1SCatalin Marinas 73308e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 73408e875c1SCatalin Marinas { 73545ed695aSNicolas Pitre __smp_cross_call = fn; 73608e875c1SCatalin Marinas } 73708e875c1SCatalin Marinas 73845ed695aSNicolas Pitre static const char *ipi_types[NR_IPI] __tracepoint_string = { 73945ed695aSNicolas Pitre #define S(x,s) [x] = s 74008e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 74108e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 74208e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 7431f85008eSLorenzo Pieralisi S(IPI_TIMER, "Timer broadcast interrupts"), 744eb631bb5SLarry Bassel S(IPI_IRQ_WORK, "IRQ work interrupts"), 7455e89c55eSLorenzo Pieralisi S(IPI_WAKEUP, "CPU wake-up interrupts"), 74608e875c1SCatalin Marinas }; 74708e875c1SCatalin Marinas 74845ed695aSNicolas Pitre static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) 74945ed695aSNicolas Pitre { 75045ed695aSNicolas Pitre trace_ipi_raise(target, ipi_types[ipinr]); 75145ed695aSNicolas Pitre __smp_cross_call(target, ipinr); 75245ed695aSNicolas Pitre } 75345ed695aSNicolas Pitre 75408e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 75508e875c1SCatalin Marinas { 75608e875c1SCatalin Marinas unsigned int cpu, i; 75708e875c1SCatalin Marinas 75808e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 75945ed695aSNicolas Pitre seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, 76008e875c1SCatalin Marinas prec >= 4 ? " " : ""); 76167317c26SSudeep KarkadaNagesha for_each_online_cpu(cpu) 76208e875c1SCatalin Marinas seq_printf(p, "%10u ", 76308e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 76408e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 76508e875c1SCatalin Marinas } 76608e875c1SCatalin Marinas } 76708e875c1SCatalin Marinas 76808e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 76908e875c1SCatalin Marinas { 77008e875c1SCatalin Marinas u64 sum = 0; 77108e875c1SCatalin Marinas int i; 77208e875c1SCatalin Marinas 77308e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 77408e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 77508e875c1SCatalin Marinas 77608e875c1SCatalin Marinas return sum; 77708e875c1SCatalin Marinas } 77808e875c1SCatalin Marinas 77945ed695aSNicolas Pitre void arch_send_call_function_ipi_mask(const struct cpumask *mask) 78045ed695aSNicolas Pitre { 78145ed695aSNicolas Pitre smp_cross_call(mask, IPI_CALL_FUNC); 78245ed695aSNicolas Pitre } 78345ed695aSNicolas Pitre 78445ed695aSNicolas Pitre void arch_send_call_function_single_ipi(int cpu) 78545ed695aSNicolas Pitre { 7860aaf0daeSJiang Liu smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC); 78745ed695aSNicolas Pitre } 78845ed695aSNicolas Pitre 7895e89c55eSLorenzo Pieralisi #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL 7905e89c55eSLorenzo Pieralisi void arch_send_wakeup_ipi_mask(const struct cpumask *mask) 7915e89c55eSLorenzo Pieralisi { 7925e89c55eSLorenzo Pieralisi smp_cross_call(mask, IPI_WAKEUP); 7935e89c55eSLorenzo Pieralisi } 7945e89c55eSLorenzo Pieralisi #endif 7955e89c55eSLorenzo Pieralisi 79645ed695aSNicolas Pitre #ifdef CONFIG_IRQ_WORK 79745ed695aSNicolas Pitre void arch_irq_work_raise(void) 79845ed695aSNicolas Pitre { 79945ed695aSNicolas Pitre if (__smp_cross_call) 80045ed695aSNicolas Pitre smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); 80145ed695aSNicolas Pitre } 80245ed695aSNicolas Pitre #endif 80345ed695aSNicolas Pitre 80408e875c1SCatalin Marinas /* 80508e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 80608e875c1SCatalin Marinas */ 80708e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 80808e875c1SCatalin Marinas { 80908e875c1SCatalin Marinas set_cpu_online(cpu, false); 81008e875c1SCatalin Marinas 81108e875c1SCatalin Marinas local_irq_disable(); 81208e875c1SCatalin Marinas 81308e875c1SCatalin Marinas while (1) 81408e875c1SCatalin Marinas cpu_relax(); 81508e875c1SCatalin Marinas } 81608e875c1SCatalin Marinas 81708e875c1SCatalin Marinas /* 81808e875c1SCatalin Marinas * Main handler for inter-processor interrupts 81908e875c1SCatalin Marinas */ 82008e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 82108e875c1SCatalin Marinas { 82208e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 82308e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 82408e875c1SCatalin Marinas 82545ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) { 826be081d9bSStephen Boyd trace_ipi_entry_rcuidle(ipi_types[ipinr]); 82745ed695aSNicolas Pitre __inc_irq_stat(cpu, ipi_irqs[ipinr]); 82845ed695aSNicolas Pitre } 82908e875c1SCatalin Marinas 83008e875c1SCatalin Marinas switch (ipinr) { 83108e875c1SCatalin Marinas case IPI_RESCHEDULE: 83208e875c1SCatalin Marinas scheduler_ipi(); 83308e875c1SCatalin Marinas break; 83408e875c1SCatalin Marinas 83508e875c1SCatalin Marinas case IPI_CALL_FUNC: 83608e875c1SCatalin Marinas irq_enter(); 83708e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 83808e875c1SCatalin Marinas irq_exit(); 83908e875c1SCatalin Marinas break; 84008e875c1SCatalin Marinas 84108e875c1SCatalin Marinas case IPI_CPU_STOP: 84208e875c1SCatalin Marinas irq_enter(); 84308e875c1SCatalin Marinas ipi_cpu_stop(cpu); 84408e875c1SCatalin Marinas irq_exit(); 84508e875c1SCatalin Marinas break; 84608e875c1SCatalin Marinas 8471f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 8481f85008eSLorenzo Pieralisi case IPI_TIMER: 8491f85008eSLorenzo Pieralisi irq_enter(); 8501f85008eSLorenzo Pieralisi tick_receive_broadcast(); 8511f85008eSLorenzo Pieralisi irq_exit(); 8521f85008eSLorenzo Pieralisi break; 8531f85008eSLorenzo Pieralisi #endif 8541f85008eSLorenzo Pieralisi 855eb631bb5SLarry Bassel #ifdef CONFIG_IRQ_WORK 856eb631bb5SLarry Bassel case IPI_IRQ_WORK: 857eb631bb5SLarry Bassel irq_enter(); 858eb631bb5SLarry Bassel irq_work_run(); 859eb631bb5SLarry Bassel irq_exit(); 860eb631bb5SLarry Bassel break; 861eb631bb5SLarry Bassel #endif 862eb631bb5SLarry Bassel 8635e89c55eSLorenzo Pieralisi #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL 8645e89c55eSLorenzo Pieralisi case IPI_WAKEUP: 8655e89c55eSLorenzo Pieralisi WARN_ONCE(!acpi_parking_protocol_valid(cpu), 8665e89c55eSLorenzo Pieralisi "CPU%u: Wake-up IPI outside the ACPI parking protocol\n", 8675e89c55eSLorenzo Pieralisi cpu); 8685e89c55eSLorenzo Pieralisi break; 8695e89c55eSLorenzo Pieralisi #endif 8705e89c55eSLorenzo Pieralisi 87108e875c1SCatalin Marinas default: 87208e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 87308e875c1SCatalin Marinas break; 87408e875c1SCatalin Marinas } 87545ed695aSNicolas Pitre 87645ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) 877be081d9bSStephen Boyd trace_ipi_exit_rcuidle(ipi_types[ipinr]); 87808e875c1SCatalin Marinas set_irq_regs(old_regs); 87908e875c1SCatalin Marinas } 88008e875c1SCatalin Marinas 88108e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 88208e875c1SCatalin Marinas { 88308e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 88408e875c1SCatalin Marinas } 88508e875c1SCatalin Marinas 8861f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 8871f85008eSLorenzo Pieralisi void tick_broadcast(const struct cpumask *mask) 8881f85008eSLorenzo Pieralisi { 8891f85008eSLorenzo Pieralisi smp_cross_call(mask, IPI_TIMER); 8901f85008eSLorenzo Pieralisi } 8911f85008eSLorenzo Pieralisi #endif 8921f85008eSLorenzo Pieralisi 89308e875c1SCatalin Marinas void smp_send_stop(void) 89408e875c1SCatalin Marinas { 89508e875c1SCatalin Marinas unsigned long timeout; 89608e875c1SCatalin Marinas 89708e875c1SCatalin Marinas if (num_online_cpus() > 1) { 89808e875c1SCatalin Marinas cpumask_t mask; 89908e875c1SCatalin Marinas 90008e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 901434ed7f4SRusty Russell cpumask_clear_cpu(smp_processor_id(), &mask); 90208e875c1SCatalin Marinas 90382611c14SJan Glauber if (system_state == SYSTEM_BOOTING || 90482611c14SJan Glauber system_state == SYSTEM_RUNNING) 90582611c14SJan Glauber pr_crit("SMP: stopping secondary CPUs\n"); 90608e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 90708e875c1SCatalin Marinas } 90808e875c1SCatalin Marinas 90908e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 91008e875c1SCatalin Marinas timeout = USEC_PER_SEC; 91108e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 91208e875c1SCatalin Marinas udelay(1); 91308e875c1SCatalin Marinas 91408e875c1SCatalin Marinas if (num_online_cpus() > 1) 91582611c14SJan Glauber pr_warning("SMP: failed to stop secondary CPUs %*pbl\n", 91682611c14SJan Glauber cpumask_pr_args(cpu_online_mask)); 91708e875c1SCatalin Marinas } 91808e875c1SCatalin Marinas 91908e875c1SCatalin Marinas /* 92008e875c1SCatalin Marinas * not supported here 92108e875c1SCatalin Marinas */ 92208e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 92308e875c1SCatalin Marinas { 92408e875c1SCatalin Marinas return -EINVAL; 92508e875c1SCatalin Marinas } 9265c492c3fSJames Morse 9275c492c3fSJames Morse static bool have_cpu_die(void) 9285c492c3fSJames Morse { 9295c492c3fSJames Morse #ifdef CONFIG_HOTPLUG_CPU 9305c492c3fSJames Morse int any_cpu = raw_smp_processor_id(); 9315c492c3fSJames Morse 9325c492c3fSJames Morse if (cpu_ops[any_cpu]->cpu_die) 9335c492c3fSJames Morse return true; 9345c492c3fSJames Morse #endif 9355c492c3fSJames Morse return false; 9365c492c3fSJames Morse } 9375c492c3fSJames Morse 9385c492c3fSJames Morse bool cpus_are_stuck_in_kernel(void) 9395c492c3fSJames Morse { 9405c492c3fSJames Morse bool smp_spin_tables = (num_possible_cpus() > 1 && !have_cpu_die()); 9415c492c3fSJames Morse 9425c492c3fSJames Morse return !!cpus_stuck_in_kernel || smp_spin_tables; 9435c492c3fSJames Morse } 944