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> 4808e875c1SCatalin Marinas #include <asm/pgtable.h> 4908e875c1SCatalin Marinas #include <asm/pgalloc.h> 5008e875c1SCatalin Marinas #include <asm/processor.h> 514c7aa002SJavi Merino #include <asm/smp_plat.h> 5208e875c1SCatalin Marinas #include <asm/sections.h> 5308e875c1SCatalin Marinas #include <asm/tlbflush.h> 5408e875c1SCatalin Marinas #include <asm/ptrace.h> 55*377bcff9SJonas Rabenstein #include <asm/virt.h> 5608e875c1SCatalin Marinas 5745ed695aSNicolas Pitre #define CREATE_TRACE_POINTS 5845ed695aSNicolas Pitre #include <trace/events/ipi.h> 5945ed695aSNicolas Pitre 6008e875c1SCatalin Marinas /* 6108e875c1SCatalin Marinas * as from 2.5, kernels no longer have an init_tasks structure 6208e875c1SCatalin Marinas * so we need some other way of telling a new secondary core 6308e875c1SCatalin Marinas * where to place its SVC stack 6408e875c1SCatalin Marinas */ 6508e875c1SCatalin Marinas struct secondary_data secondary_data; 6608e875c1SCatalin Marinas 6708e875c1SCatalin Marinas enum ipi_msg_type { 6808e875c1SCatalin Marinas IPI_RESCHEDULE, 6908e875c1SCatalin Marinas IPI_CALL_FUNC, 7008e875c1SCatalin Marinas IPI_CPU_STOP, 711f85008eSLorenzo Pieralisi IPI_TIMER, 72eb631bb5SLarry Bassel IPI_IRQ_WORK, 7308e875c1SCatalin Marinas }; 7408e875c1SCatalin Marinas 7508e875c1SCatalin Marinas /* 7608e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 7708e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 7808e875c1SCatalin Marinas */ 79b8c6453aSPaul Gortmaker static int boot_secondary(unsigned int cpu, struct task_struct *idle) 8008e875c1SCatalin Marinas { 81652af899SMark Rutland if (cpu_ops[cpu]->cpu_boot) 82652af899SMark Rutland return cpu_ops[cpu]->cpu_boot(cpu); 8308e875c1SCatalin Marinas 84652af899SMark Rutland return -EOPNOTSUPP; 8508e875c1SCatalin Marinas } 8608e875c1SCatalin Marinas 8708e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 8808e875c1SCatalin Marinas 89b8c6453aSPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *idle) 9008e875c1SCatalin Marinas { 9108e875c1SCatalin Marinas int ret; 9208e875c1SCatalin Marinas 9308e875c1SCatalin Marinas /* 9408e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 9508e875c1SCatalin Marinas * page tables. 9608e875c1SCatalin Marinas */ 9708e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 9808e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 9908e875c1SCatalin Marinas 10008e875c1SCatalin Marinas /* 10108e875c1SCatalin Marinas * Now bring the CPU into our world. 10208e875c1SCatalin Marinas */ 10308e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 10408e875c1SCatalin Marinas if (ret == 0) { 10508e875c1SCatalin Marinas /* 10608e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 10708e875c1SCatalin Marinas * time out. 10808e875c1SCatalin Marinas */ 10908e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 11008e875c1SCatalin Marinas msecs_to_jiffies(1000)); 11108e875c1SCatalin Marinas 11208e875c1SCatalin Marinas if (!cpu_online(cpu)) { 11308e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 11408e875c1SCatalin Marinas ret = -EIO; 11508e875c1SCatalin Marinas } 11608e875c1SCatalin Marinas } else { 11708e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 11808e875c1SCatalin Marinas } 11908e875c1SCatalin Marinas 12008e875c1SCatalin Marinas secondary_data.stack = NULL; 12108e875c1SCatalin Marinas 12208e875c1SCatalin Marinas return ret; 12308e875c1SCatalin Marinas } 12408e875c1SCatalin Marinas 125f6e763b9SMark Brown static void smp_store_cpu_info(unsigned int cpuid) 126f6e763b9SMark Brown { 127f6e763b9SMark Brown store_cpu_topology(cpuid); 128f6e763b9SMark Brown } 129f6e763b9SMark Brown 13008e875c1SCatalin Marinas /* 13108e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 13208e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 13308e875c1SCatalin Marinas */ 134b8c6453aSPaul Gortmaker asmlinkage void secondary_start_kernel(void) 13508e875c1SCatalin Marinas { 13608e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 13708e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 13808e875c1SCatalin Marinas 13908e875c1SCatalin Marinas /* 14008e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 14108e875c1SCatalin Marinas * reference and switch to it. 14208e875c1SCatalin Marinas */ 14308e875c1SCatalin Marinas atomic_inc(&mm->mm_count); 14408e875c1SCatalin Marinas current->active_mm = mm; 14508e875c1SCatalin Marinas cpumask_set_cpu(cpu, mm_cpumask(mm)); 14608e875c1SCatalin Marinas 14771586276SWill Deacon set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 14871586276SWill Deacon printk("CPU%u: Booted secondary processor\n", cpu); 14971586276SWill Deacon 15008e875c1SCatalin Marinas /* 15108e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 15208e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 15308e875c1SCatalin Marinas */ 15408e875c1SCatalin Marinas cpu_set_reserved_ttbr0(); 15508e875c1SCatalin Marinas flush_tlb_all(); 156dd006da2SArd Biesheuvel cpu_set_default_tcr_t0sz(); 15708e875c1SCatalin Marinas 15808e875c1SCatalin Marinas preempt_disable(); 15908e875c1SCatalin Marinas trace_hardirqs_off(); 16008e875c1SCatalin Marinas 161652af899SMark Rutland if (cpu_ops[cpu]->cpu_postboot) 162652af899SMark Rutland cpu_ops[cpu]->cpu_postboot(); 16308e875c1SCatalin Marinas 16408e875c1SCatalin Marinas /* 165df857416SMark Rutland * Log the CPU info before it is marked online and might get read. 166df857416SMark Rutland */ 167df857416SMark Rutland cpuinfo_store_cpu(); 168df857416SMark Rutland 169df857416SMark Rutland /* 1707ade67b5SMarc Zyngier * Enable GIC and timers. 1717ade67b5SMarc Zyngier */ 1727ade67b5SMarc Zyngier notify_cpu_starting(cpu); 1737ade67b5SMarc Zyngier 174f6e763b9SMark Brown smp_store_cpu_info(cpu); 175f6e763b9SMark Brown 1767ade67b5SMarc Zyngier /* 17708e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 17808e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 17908e875c1SCatalin Marinas * before we continue. 18008e875c1SCatalin Marinas */ 18108e875c1SCatalin Marinas set_cpu_online(cpu, true); 182b3770b32SWill Deacon complete(&cpu_running); 18308e875c1SCatalin Marinas 184d8ed442aSVijaya Kumar K local_dbg_enable(); 18553ae3acdSCatalin Marinas local_irq_enable(); 186b3bf6aa7SCatalin Marinas local_async_enable(); 18753ae3acdSCatalin Marinas 18853ae3acdSCatalin Marinas /* 18908e875c1SCatalin Marinas * OK, it's off to the idle thread for us 19008e875c1SCatalin Marinas */ 1910087298fSThomas Gleixner cpu_startup_entry(CPUHP_ONLINE); 19208e875c1SCatalin Marinas } 19308e875c1SCatalin Marinas 1949327e2c6SMark Rutland #ifdef CONFIG_HOTPLUG_CPU 1959327e2c6SMark Rutland static int op_cpu_disable(unsigned int cpu) 1969327e2c6SMark Rutland { 1979327e2c6SMark Rutland /* 1989327e2c6SMark Rutland * If we don't have a cpu_die method, abort before we reach the point 1999327e2c6SMark Rutland * of no return. CPU0 may not have an cpu_ops, so test for it. 2009327e2c6SMark Rutland */ 2019327e2c6SMark Rutland if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) 2029327e2c6SMark Rutland return -EOPNOTSUPP; 2039327e2c6SMark Rutland 2049327e2c6SMark Rutland /* 2059327e2c6SMark Rutland * We may need to abort a hot unplug for some other mechanism-specific 2069327e2c6SMark Rutland * reason. 2079327e2c6SMark Rutland */ 2089327e2c6SMark Rutland if (cpu_ops[cpu]->cpu_disable) 2099327e2c6SMark Rutland return cpu_ops[cpu]->cpu_disable(cpu); 2109327e2c6SMark Rutland 2119327e2c6SMark Rutland return 0; 2129327e2c6SMark Rutland } 2139327e2c6SMark Rutland 2149327e2c6SMark Rutland /* 2159327e2c6SMark Rutland * __cpu_disable runs on the processor to be shutdown. 2169327e2c6SMark Rutland */ 2179327e2c6SMark Rutland int __cpu_disable(void) 2189327e2c6SMark Rutland { 2199327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 2209327e2c6SMark Rutland int ret; 2219327e2c6SMark Rutland 2229327e2c6SMark Rutland ret = op_cpu_disable(cpu); 2239327e2c6SMark Rutland if (ret) 2249327e2c6SMark Rutland return ret; 2259327e2c6SMark Rutland 2269327e2c6SMark Rutland /* 2279327e2c6SMark Rutland * Take this CPU offline. Once we clear this, we can't return, 2289327e2c6SMark Rutland * and we must not schedule until we're ready to give up the cpu. 2299327e2c6SMark Rutland */ 2309327e2c6SMark Rutland set_cpu_online(cpu, false); 2319327e2c6SMark Rutland 2329327e2c6SMark Rutland /* 2339327e2c6SMark Rutland * OK - migrate IRQs away from this CPU 2349327e2c6SMark Rutland */ 2359327e2c6SMark Rutland migrate_irqs(); 2369327e2c6SMark Rutland 2379327e2c6SMark Rutland /* 2389327e2c6SMark Rutland * Remove this CPU from the vm mask set of all processes. 2399327e2c6SMark Rutland */ 2409327e2c6SMark Rutland clear_tasks_mm_cpumask(cpu); 2419327e2c6SMark Rutland 2429327e2c6SMark Rutland return 0; 2439327e2c6SMark Rutland } 2449327e2c6SMark Rutland 245c814ca02SAshwin Chaugule static int op_cpu_kill(unsigned int cpu) 246c814ca02SAshwin Chaugule { 247c814ca02SAshwin Chaugule /* 248c814ca02SAshwin Chaugule * If we have no means of synchronising with the dying CPU, then assume 249c814ca02SAshwin Chaugule * that it is really dead. We can only wait for an arbitrary length of 250c814ca02SAshwin Chaugule * time and hope that it's dead, so let's skip the wait and just hope. 251c814ca02SAshwin Chaugule */ 252c814ca02SAshwin Chaugule if (!cpu_ops[cpu]->cpu_kill) 2536b99c68cSMark Rutland return 0; 254c814ca02SAshwin Chaugule 255c814ca02SAshwin Chaugule return cpu_ops[cpu]->cpu_kill(cpu); 256c814ca02SAshwin Chaugule } 257c814ca02SAshwin Chaugule 2589327e2c6SMark Rutland /* 2599327e2c6SMark Rutland * called on the thread which is asking for a CPU to be shutdown - 2609327e2c6SMark Rutland * waits until shutdown has completed, or it is timed out. 2619327e2c6SMark Rutland */ 2629327e2c6SMark Rutland void __cpu_die(unsigned int cpu) 2639327e2c6SMark Rutland { 2646b99c68cSMark Rutland int err; 2656b99c68cSMark Rutland 26605981277SPaul E. McKenney if (!cpu_wait_death(cpu, 5)) { 2679327e2c6SMark Rutland pr_crit("CPU%u: cpu didn't die\n", cpu); 2689327e2c6SMark Rutland return; 2699327e2c6SMark Rutland } 2709327e2c6SMark Rutland pr_notice("CPU%u: shutdown\n", cpu); 271c814ca02SAshwin Chaugule 272c814ca02SAshwin Chaugule /* 273c814ca02SAshwin Chaugule * Now that the dying CPU is beyond the point of no return w.r.t. 274c814ca02SAshwin Chaugule * in-kernel synchronisation, try to get the firwmare to help us to 275c814ca02SAshwin Chaugule * verify that it has really left the kernel before we consider 276c814ca02SAshwin Chaugule * clobbering anything it might still be using. 277c814ca02SAshwin Chaugule */ 2786b99c68cSMark Rutland err = op_cpu_kill(cpu); 2796b99c68cSMark Rutland if (err) 2806b99c68cSMark Rutland pr_warn("CPU%d may not have shut down cleanly: %d\n", 2816b99c68cSMark Rutland cpu, err); 2829327e2c6SMark Rutland } 2839327e2c6SMark Rutland 2849327e2c6SMark Rutland /* 2859327e2c6SMark Rutland * Called from the idle thread for the CPU which has been shutdown. 2869327e2c6SMark Rutland * 2879327e2c6SMark Rutland * Note that we disable IRQs here, but do not re-enable them 2889327e2c6SMark Rutland * before returning to the caller. This is also the behaviour 2899327e2c6SMark Rutland * of the other hotplug-cpu capable cores, so presumably coming 2909327e2c6SMark Rutland * out of idle fixes this. 2919327e2c6SMark Rutland */ 2929327e2c6SMark Rutland void cpu_die(void) 2939327e2c6SMark Rutland { 2949327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 2959327e2c6SMark Rutland 2969327e2c6SMark Rutland idle_task_exit(); 2979327e2c6SMark Rutland 2989327e2c6SMark Rutland local_irq_disable(); 2999327e2c6SMark Rutland 3009327e2c6SMark Rutland /* Tell __cpu_die() that this CPU is now safe to dispose of */ 30105981277SPaul E. McKenney (void)cpu_report_death(); 3029327e2c6SMark Rutland 3039327e2c6SMark Rutland /* 3049327e2c6SMark Rutland * Actually shutdown the CPU. This must never fail. The specific hotplug 3059327e2c6SMark Rutland * mechanism must perform all required cache maintenance to ensure that 3069327e2c6SMark Rutland * no dirty lines are lost in the process of shutting down the CPU. 3079327e2c6SMark Rutland */ 3089327e2c6SMark Rutland cpu_ops[cpu]->cpu_die(cpu); 3099327e2c6SMark Rutland 3109327e2c6SMark Rutland BUG(); 3119327e2c6SMark Rutland } 3129327e2c6SMark Rutland #endif 3139327e2c6SMark Rutland 314*377bcff9SJonas Rabenstein static void __init hyp_mode_check(void) 315*377bcff9SJonas Rabenstein { 316*377bcff9SJonas Rabenstein if (is_hyp_mode_available()) 317*377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL2\n"); 318*377bcff9SJonas Rabenstein else if (is_hyp_mode_mismatched()) 319*377bcff9SJonas Rabenstein WARN_TAINT(1, TAINT_CPU_OUT_OF_SPEC, 320*377bcff9SJonas Rabenstein "CPU: CPUs started in inconsistent modes"); 321*377bcff9SJonas Rabenstein else 322*377bcff9SJonas Rabenstein pr_info("CPU: All CPU(s) started at EL1\n"); 323*377bcff9SJonas Rabenstein } 324*377bcff9SJonas Rabenstein 32508e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 32608e875c1SCatalin Marinas { 327326b16dbSWill Deacon pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); 328*377bcff9SJonas Rabenstein hyp_mode_check(); 329*377bcff9SJonas Rabenstein apply_alternatives_all(); 33008e875c1SCatalin Marinas } 33108e875c1SCatalin Marinas 33208e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 33308e875c1SCatalin Marinas { 33471586276SWill Deacon set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 33508e875c1SCatalin Marinas } 33608e875c1SCatalin Marinas 3370f078336SLorenzo Pieralisi static u64 __init of_get_cpu_mpidr(struct device_node *dn) 3380f078336SLorenzo Pieralisi { 3390f078336SLorenzo Pieralisi const __be32 *cell; 3400f078336SLorenzo Pieralisi u64 hwid; 3410f078336SLorenzo Pieralisi 3420f078336SLorenzo Pieralisi /* 3430f078336SLorenzo Pieralisi * A cpu node with missing "reg" property is 3440f078336SLorenzo Pieralisi * considered invalid to build a cpu_logical_map 3450f078336SLorenzo Pieralisi * entry. 3460f078336SLorenzo Pieralisi */ 3470f078336SLorenzo Pieralisi cell = of_get_property(dn, "reg", NULL); 3480f078336SLorenzo Pieralisi if (!cell) { 3490f078336SLorenzo Pieralisi pr_err("%s: missing reg property\n", dn->full_name); 3500f078336SLorenzo Pieralisi return INVALID_HWID; 3510f078336SLorenzo Pieralisi } 3520f078336SLorenzo Pieralisi 3530f078336SLorenzo Pieralisi hwid = of_read_number(cell, of_n_addr_cells(dn)); 3540f078336SLorenzo Pieralisi /* 3550f078336SLorenzo Pieralisi * Non affinity bits must be set to 0 in the DT 3560f078336SLorenzo Pieralisi */ 3570f078336SLorenzo Pieralisi if (hwid & ~MPIDR_HWID_BITMASK) { 3580f078336SLorenzo Pieralisi pr_err("%s: invalid reg property\n", dn->full_name); 3590f078336SLorenzo Pieralisi return INVALID_HWID; 3600f078336SLorenzo Pieralisi } 3610f078336SLorenzo Pieralisi return hwid; 3620f078336SLorenzo Pieralisi } 3630f078336SLorenzo Pieralisi 3640f078336SLorenzo Pieralisi /* 3650f078336SLorenzo Pieralisi * Duplicate MPIDRs are a recipe for disaster. Scan all initialized 3660f078336SLorenzo Pieralisi * entries and check for duplicates. If any is found just ignore the 3670f078336SLorenzo Pieralisi * cpu. cpu_logical_map was initialized to INVALID_HWID to avoid 3680f078336SLorenzo Pieralisi * matching valid MPIDR values. 3690f078336SLorenzo Pieralisi */ 3700f078336SLorenzo Pieralisi static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid) 3710f078336SLorenzo Pieralisi { 3720f078336SLorenzo Pieralisi unsigned int i; 3730f078336SLorenzo Pieralisi 3740f078336SLorenzo Pieralisi for (i = 1; (i < cpu) && (i < NR_CPUS); i++) 3750f078336SLorenzo Pieralisi if (cpu_logical_map(i) == hwid) 3760f078336SLorenzo Pieralisi return true; 3770f078336SLorenzo Pieralisi return false; 3780f078336SLorenzo Pieralisi } 3790f078336SLorenzo Pieralisi 38008e875c1SCatalin Marinas /* 381819a8826SLorenzo Pieralisi * Initialize cpu operations for a logical cpu and 382819a8826SLorenzo Pieralisi * set it in the possible mask on success 383819a8826SLorenzo Pieralisi */ 384819a8826SLorenzo Pieralisi static int __init smp_cpu_setup(int cpu) 385819a8826SLorenzo Pieralisi { 386819a8826SLorenzo Pieralisi if (cpu_read_ops(cpu)) 387819a8826SLorenzo Pieralisi return -ENODEV; 388819a8826SLorenzo Pieralisi 389819a8826SLorenzo Pieralisi if (cpu_ops[cpu]->cpu_init(cpu)) 390819a8826SLorenzo Pieralisi return -ENODEV; 391819a8826SLorenzo Pieralisi 392819a8826SLorenzo Pieralisi set_cpu_possible(cpu, true); 393819a8826SLorenzo Pieralisi 394819a8826SLorenzo Pieralisi return 0; 395819a8826SLorenzo Pieralisi } 396819a8826SLorenzo Pieralisi 3970f078336SLorenzo Pieralisi static bool bootcpu_valid __initdata; 3980f078336SLorenzo Pieralisi static unsigned int cpu_count = 1; 3990f078336SLorenzo Pieralisi 4000f078336SLorenzo Pieralisi #ifdef CONFIG_ACPI 4010f078336SLorenzo Pieralisi /* 4020f078336SLorenzo Pieralisi * acpi_map_gic_cpu_interface - parse processor MADT entry 4030f078336SLorenzo Pieralisi * 4040f078336SLorenzo Pieralisi * Carry out sanity checks on MADT processor entry and initialize 4050f078336SLorenzo Pieralisi * cpu_logical_map on success 4060f078336SLorenzo Pieralisi */ 4070f078336SLorenzo Pieralisi static void __init 4080f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) 4090f078336SLorenzo Pieralisi { 4100f078336SLorenzo Pieralisi u64 hwid = processor->arm_mpidr; 4110f078336SLorenzo Pieralisi 412f9058929SHanjun Guo if (!(processor->flags & ACPI_MADT_ENABLED)) { 413f9058929SHanjun Guo pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid); 4140f078336SLorenzo Pieralisi return; 4150f078336SLorenzo Pieralisi } 4160f078336SLorenzo Pieralisi 417f9058929SHanjun Guo if (hwid & ~MPIDR_HWID_BITMASK || hwid == INVALID_HWID) { 418f9058929SHanjun Guo pr_err("skipping CPU entry with invalid MPIDR 0x%llx\n", hwid); 4190f078336SLorenzo Pieralisi return; 4200f078336SLorenzo Pieralisi } 4210f078336SLorenzo Pieralisi 4220f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 4230f078336SLorenzo Pieralisi pr_err("duplicate CPU MPIDR 0x%llx in MADT\n", hwid); 4240f078336SLorenzo Pieralisi return; 4250f078336SLorenzo Pieralisi } 4260f078336SLorenzo Pieralisi 4270f078336SLorenzo Pieralisi /* Check if GICC structure of boot CPU is available in the MADT */ 4280f078336SLorenzo Pieralisi if (cpu_logical_map(0) == hwid) { 4290f078336SLorenzo Pieralisi if (bootcpu_valid) { 4300f078336SLorenzo Pieralisi pr_err("duplicate boot CPU MPIDR: 0x%llx in MADT\n", 4310f078336SLorenzo Pieralisi hwid); 4320f078336SLorenzo Pieralisi return; 4330f078336SLorenzo Pieralisi } 4340f078336SLorenzo Pieralisi bootcpu_valid = true; 4350f078336SLorenzo Pieralisi return; 4360f078336SLorenzo Pieralisi } 4370f078336SLorenzo Pieralisi 4380f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 4390f078336SLorenzo Pieralisi return; 4400f078336SLorenzo Pieralisi 4410f078336SLorenzo Pieralisi /* map the logical cpu id to cpu MPIDR */ 4420f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 4430f078336SLorenzo Pieralisi 4440f078336SLorenzo Pieralisi cpu_count++; 4450f078336SLorenzo Pieralisi } 4460f078336SLorenzo Pieralisi 4470f078336SLorenzo Pieralisi static int __init 4480f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, 4490f078336SLorenzo Pieralisi const unsigned long end) 4500f078336SLorenzo Pieralisi { 4510f078336SLorenzo Pieralisi struct acpi_madt_generic_interrupt *processor; 4520f078336SLorenzo Pieralisi 4530f078336SLorenzo Pieralisi processor = (struct acpi_madt_generic_interrupt *)header; 45499e3e3aeSAl Stone if (BAD_MADT_GICC_ENTRY(processor, end)) 4550f078336SLorenzo Pieralisi return -EINVAL; 4560f078336SLorenzo Pieralisi 4570f078336SLorenzo Pieralisi acpi_table_print_madt_entry(header); 4580f078336SLorenzo Pieralisi 4590f078336SLorenzo Pieralisi acpi_map_gic_cpu_interface(processor); 4600f078336SLorenzo Pieralisi 4610f078336SLorenzo Pieralisi return 0; 4620f078336SLorenzo Pieralisi } 4630f078336SLorenzo Pieralisi #else 4640f078336SLorenzo Pieralisi #define acpi_table_parse_madt(...) do { } while (0) 4650f078336SLorenzo Pieralisi #endif 4660f078336SLorenzo Pieralisi 467819a8826SLorenzo Pieralisi /* 4684c7aa002SJavi Merino * Enumerate the possible CPU set from the device tree and build the 4694c7aa002SJavi Merino * cpu logical map array containing MPIDR values related to logical 4704c7aa002SJavi Merino * cpus. Assumes that cpu_logical_map(0) has already been initialized. 47108e875c1SCatalin Marinas */ 4720f078336SLorenzo Pieralisi void __init of_parse_and_init_cpus(void) 47308e875c1SCatalin Marinas { 47408e875c1SCatalin Marinas struct device_node *dn = NULL; 47508e875c1SCatalin Marinas 47608e875c1SCatalin Marinas while ((dn = of_find_node_by_type(dn, "cpu"))) { 4770f078336SLorenzo Pieralisi u64 hwid = of_get_cpu_mpidr(dn); 4784c7aa002SJavi Merino 4790f078336SLorenzo Pieralisi if (hwid == INVALID_HWID) 4804c7aa002SJavi Merino goto next; 4814c7aa002SJavi Merino 4820f078336SLorenzo Pieralisi if (is_mpidr_duplicate(cpu_count, hwid)) { 4834c7aa002SJavi Merino pr_err("%s: duplicate cpu reg properties in the DT\n", 4844c7aa002SJavi Merino dn->full_name); 4854c7aa002SJavi Merino goto next; 4864c7aa002SJavi Merino } 4874c7aa002SJavi Merino 4884c7aa002SJavi Merino /* 4894c7aa002SJavi Merino * The numbering scheme requires that the boot CPU 4904c7aa002SJavi Merino * must be assigned logical id 0. Record it so that 4914c7aa002SJavi Merino * the logical map built from DT is validated and can 4924c7aa002SJavi Merino * be used. 4934c7aa002SJavi Merino */ 4944c7aa002SJavi Merino if (hwid == cpu_logical_map(0)) { 4954c7aa002SJavi Merino if (bootcpu_valid) { 4964c7aa002SJavi Merino pr_err("%s: duplicate boot cpu reg property in DT\n", 4974c7aa002SJavi Merino dn->full_name); 4984c7aa002SJavi Merino goto next; 4994c7aa002SJavi Merino } 5004c7aa002SJavi Merino 5014c7aa002SJavi Merino bootcpu_valid = true; 5024c7aa002SJavi Merino 5034c7aa002SJavi Merino /* 5044c7aa002SJavi Merino * cpu_logical_map has already been 5054c7aa002SJavi Merino * initialized and the boot cpu doesn't need 5064c7aa002SJavi Merino * the enable-method so continue without 5074c7aa002SJavi Merino * incrementing cpu. 5084c7aa002SJavi Merino */ 5094c7aa002SJavi Merino continue; 5104c7aa002SJavi Merino } 5114c7aa002SJavi Merino 5120f078336SLorenzo Pieralisi if (cpu_count >= NR_CPUS) 51308e875c1SCatalin Marinas goto next; 51408e875c1SCatalin Marinas 5154c7aa002SJavi Merino pr_debug("cpu logical map 0x%llx\n", hwid); 5160f078336SLorenzo Pieralisi cpu_logical_map(cpu_count) = hwid; 51708e875c1SCatalin Marinas next: 5180f078336SLorenzo Pieralisi cpu_count++; 5190f078336SLorenzo Pieralisi } 52008e875c1SCatalin Marinas } 52108e875c1SCatalin Marinas 5220f078336SLorenzo Pieralisi /* 5230f078336SLorenzo Pieralisi * Enumerate the possible CPU set from the device tree or ACPI and build the 5240f078336SLorenzo Pieralisi * cpu logical map array containing MPIDR values related to logical 5250f078336SLorenzo Pieralisi * cpus. Assumes that cpu_logical_map(0) has already been initialized. 5260f078336SLorenzo Pieralisi */ 5270f078336SLorenzo Pieralisi void __init smp_init_cpus(void) 5280f078336SLorenzo Pieralisi { 5290f078336SLorenzo Pieralisi int i; 5300f078336SLorenzo Pieralisi 5310f078336SLorenzo Pieralisi if (acpi_disabled) 5320f078336SLorenzo Pieralisi of_parse_and_init_cpus(); 5330f078336SLorenzo Pieralisi else 5340f078336SLorenzo Pieralisi /* 5350f078336SLorenzo Pieralisi * do a walk of MADT to determine how many CPUs 5360f078336SLorenzo Pieralisi * we have including disabled CPUs, and get information 5370f078336SLorenzo Pieralisi * we need for SMP init 5380f078336SLorenzo Pieralisi */ 5390f078336SLorenzo Pieralisi acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, 5400f078336SLorenzo Pieralisi acpi_parse_gic_cpu_interface, 0); 5410f078336SLorenzo Pieralisi 5420f078336SLorenzo Pieralisi if (cpu_count > NR_CPUS) 5430f078336SLorenzo Pieralisi pr_warn("no. of cores (%d) greater than configured maximum of %d - clipping\n", 5440f078336SLorenzo Pieralisi cpu_count, NR_CPUS); 5454c7aa002SJavi Merino 5464c7aa002SJavi Merino if (!bootcpu_valid) { 5470f078336SLorenzo Pieralisi pr_err("missing boot CPU MPIDR, not enabling secondaries\n"); 5484c7aa002SJavi Merino return; 5494c7aa002SJavi Merino } 5504c7aa002SJavi Merino 5514c7aa002SJavi Merino /* 552819a8826SLorenzo Pieralisi * We need to set the cpu_logical_map entries before enabling 553819a8826SLorenzo Pieralisi * the cpus so that cpu processor description entries (DT cpu nodes 554819a8826SLorenzo Pieralisi * and ACPI MADT entries) can be retrieved by matching the cpu hwid 555819a8826SLorenzo Pieralisi * with entries in cpu_logical_map while initializing the cpus. 556819a8826SLorenzo Pieralisi * If the cpu set-up fails, invalidate the cpu_logical_map entry. 5574c7aa002SJavi Merino */ 558819a8826SLorenzo Pieralisi for (i = 1; i < NR_CPUS; i++) { 559819a8826SLorenzo Pieralisi if (cpu_logical_map(i) != INVALID_HWID) { 560819a8826SLorenzo Pieralisi if (smp_cpu_setup(i)) 561819a8826SLorenzo Pieralisi cpu_logical_map(i) = INVALID_HWID; 562819a8826SLorenzo Pieralisi } 563819a8826SLorenzo Pieralisi } 56408e875c1SCatalin Marinas } 56508e875c1SCatalin Marinas 56608e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 56708e875c1SCatalin Marinas { 568cd1aebf5SMark Rutland int err; 569cd1aebf5SMark Rutland unsigned int cpu, ncores = num_possible_cpus(); 57008e875c1SCatalin Marinas 571f6e763b9SMark Brown init_cpu_topology(); 572f6e763b9SMark Brown 573f6e763b9SMark Brown smp_store_cpu_info(smp_processor_id()); 574f6e763b9SMark Brown 57508e875c1SCatalin Marinas /* 57608e875c1SCatalin Marinas * are we trying to boot more cores than exist? 57708e875c1SCatalin Marinas */ 57808e875c1SCatalin Marinas if (max_cpus > ncores) 57908e875c1SCatalin Marinas max_cpus = ncores; 58008e875c1SCatalin Marinas 581d329de3fSMarc Zyngier /* Don't bother if we're effectively UP */ 582d329de3fSMarc Zyngier if (max_cpus <= 1) 583d329de3fSMarc Zyngier return; 584d329de3fSMarc Zyngier 58508e875c1SCatalin Marinas /* 58608e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 58708e875c1SCatalin Marinas * actually populated at the present time) and release the 58808e875c1SCatalin Marinas * secondaries from the bootloader. 589d329de3fSMarc Zyngier * 590d329de3fSMarc Zyngier * Make sure we online at most (max_cpus - 1) additional CPUs. 59108e875c1SCatalin Marinas */ 592d329de3fSMarc Zyngier max_cpus--; 59308e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 59408e875c1SCatalin Marinas if (max_cpus == 0) 59508e875c1SCatalin Marinas break; 59608e875c1SCatalin Marinas 597d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 59808e875c1SCatalin Marinas continue; 59908e875c1SCatalin Marinas 600cd1aebf5SMark Rutland if (!cpu_ops[cpu]) 601d329de3fSMarc Zyngier continue; 602d329de3fSMarc Zyngier 603cd1aebf5SMark Rutland err = cpu_ops[cpu]->cpu_prepare(cpu); 604d329de3fSMarc Zyngier if (err) 605d329de3fSMarc Zyngier continue; 60608e875c1SCatalin Marinas 60708e875c1SCatalin Marinas set_cpu_present(cpu, true); 60808e875c1SCatalin Marinas max_cpus--; 60908e875c1SCatalin Marinas } 61008e875c1SCatalin Marinas } 61108e875c1SCatalin Marinas 61236310736SFrederic Weisbecker void (*__smp_cross_call)(const struct cpumask *, unsigned int); 61308e875c1SCatalin Marinas 61408e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 61508e875c1SCatalin Marinas { 61645ed695aSNicolas Pitre __smp_cross_call = fn; 61708e875c1SCatalin Marinas } 61808e875c1SCatalin Marinas 61945ed695aSNicolas Pitre static const char *ipi_types[NR_IPI] __tracepoint_string = { 62045ed695aSNicolas Pitre #define S(x,s) [x] = s 62108e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 62208e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 62308e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 6241f85008eSLorenzo Pieralisi S(IPI_TIMER, "Timer broadcast interrupts"), 625eb631bb5SLarry Bassel S(IPI_IRQ_WORK, "IRQ work interrupts"), 62608e875c1SCatalin Marinas }; 62708e875c1SCatalin Marinas 62845ed695aSNicolas Pitre static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) 62945ed695aSNicolas Pitre { 63045ed695aSNicolas Pitre trace_ipi_raise(target, ipi_types[ipinr]); 63145ed695aSNicolas Pitre __smp_cross_call(target, ipinr); 63245ed695aSNicolas Pitre } 63345ed695aSNicolas Pitre 63408e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 63508e875c1SCatalin Marinas { 63608e875c1SCatalin Marinas unsigned int cpu, i; 63708e875c1SCatalin Marinas 63808e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 63945ed695aSNicolas Pitre seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, 64008e875c1SCatalin Marinas prec >= 4 ? " " : ""); 64167317c26SSudeep KarkadaNagesha for_each_online_cpu(cpu) 64208e875c1SCatalin Marinas seq_printf(p, "%10u ", 64308e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 64408e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 64508e875c1SCatalin Marinas } 64608e875c1SCatalin Marinas } 64708e875c1SCatalin Marinas 64808e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 64908e875c1SCatalin Marinas { 65008e875c1SCatalin Marinas u64 sum = 0; 65108e875c1SCatalin Marinas int i; 65208e875c1SCatalin Marinas 65308e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 65408e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 65508e875c1SCatalin Marinas 65608e875c1SCatalin Marinas return sum; 65708e875c1SCatalin Marinas } 65808e875c1SCatalin Marinas 65945ed695aSNicolas Pitre void arch_send_call_function_ipi_mask(const struct cpumask *mask) 66045ed695aSNicolas Pitre { 66145ed695aSNicolas Pitre smp_cross_call(mask, IPI_CALL_FUNC); 66245ed695aSNicolas Pitre } 66345ed695aSNicolas Pitre 66445ed695aSNicolas Pitre void arch_send_call_function_single_ipi(int cpu) 66545ed695aSNicolas Pitre { 6660aaf0daeSJiang Liu smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC); 66745ed695aSNicolas Pitre } 66845ed695aSNicolas Pitre 66945ed695aSNicolas Pitre #ifdef CONFIG_IRQ_WORK 67045ed695aSNicolas Pitre void arch_irq_work_raise(void) 67145ed695aSNicolas Pitre { 67245ed695aSNicolas Pitre if (__smp_cross_call) 67345ed695aSNicolas Pitre smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); 67445ed695aSNicolas Pitre } 67545ed695aSNicolas Pitre #endif 67645ed695aSNicolas Pitre 67708e875c1SCatalin Marinas static DEFINE_RAW_SPINLOCK(stop_lock); 67808e875c1SCatalin Marinas 67908e875c1SCatalin Marinas /* 68008e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 68108e875c1SCatalin Marinas */ 68208e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 68308e875c1SCatalin Marinas { 68408e875c1SCatalin Marinas if (system_state == SYSTEM_BOOTING || 68508e875c1SCatalin Marinas system_state == SYSTEM_RUNNING) { 68608e875c1SCatalin Marinas raw_spin_lock(&stop_lock); 68708e875c1SCatalin Marinas pr_crit("CPU%u: stopping\n", cpu); 68808e875c1SCatalin Marinas dump_stack(); 68908e875c1SCatalin Marinas raw_spin_unlock(&stop_lock); 69008e875c1SCatalin Marinas } 69108e875c1SCatalin Marinas 69208e875c1SCatalin Marinas set_cpu_online(cpu, false); 69308e875c1SCatalin Marinas 69408e875c1SCatalin Marinas local_irq_disable(); 69508e875c1SCatalin Marinas 69608e875c1SCatalin Marinas while (1) 69708e875c1SCatalin Marinas cpu_relax(); 69808e875c1SCatalin Marinas } 69908e875c1SCatalin Marinas 70008e875c1SCatalin Marinas /* 70108e875c1SCatalin Marinas * Main handler for inter-processor interrupts 70208e875c1SCatalin Marinas */ 70308e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 70408e875c1SCatalin Marinas { 70508e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 70608e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 70708e875c1SCatalin Marinas 70845ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) { 709be081d9bSStephen Boyd trace_ipi_entry_rcuidle(ipi_types[ipinr]); 71045ed695aSNicolas Pitre __inc_irq_stat(cpu, ipi_irqs[ipinr]); 71145ed695aSNicolas Pitre } 71208e875c1SCatalin Marinas 71308e875c1SCatalin Marinas switch (ipinr) { 71408e875c1SCatalin Marinas case IPI_RESCHEDULE: 71508e875c1SCatalin Marinas scheduler_ipi(); 71608e875c1SCatalin Marinas break; 71708e875c1SCatalin Marinas 71808e875c1SCatalin Marinas case IPI_CALL_FUNC: 71908e875c1SCatalin Marinas irq_enter(); 72008e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 72108e875c1SCatalin Marinas irq_exit(); 72208e875c1SCatalin Marinas break; 72308e875c1SCatalin Marinas 72408e875c1SCatalin Marinas case IPI_CPU_STOP: 72508e875c1SCatalin Marinas irq_enter(); 72608e875c1SCatalin Marinas ipi_cpu_stop(cpu); 72708e875c1SCatalin Marinas irq_exit(); 72808e875c1SCatalin Marinas break; 72908e875c1SCatalin Marinas 7301f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 7311f85008eSLorenzo Pieralisi case IPI_TIMER: 7321f85008eSLorenzo Pieralisi irq_enter(); 7331f85008eSLorenzo Pieralisi tick_receive_broadcast(); 7341f85008eSLorenzo Pieralisi irq_exit(); 7351f85008eSLorenzo Pieralisi break; 7361f85008eSLorenzo Pieralisi #endif 7371f85008eSLorenzo Pieralisi 738eb631bb5SLarry Bassel #ifdef CONFIG_IRQ_WORK 739eb631bb5SLarry Bassel case IPI_IRQ_WORK: 740eb631bb5SLarry Bassel irq_enter(); 741eb631bb5SLarry Bassel irq_work_run(); 742eb631bb5SLarry Bassel irq_exit(); 743eb631bb5SLarry Bassel break; 744eb631bb5SLarry Bassel #endif 745eb631bb5SLarry Bassel 74608e875c1SCatalin Marinas default: 74708e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 74808e875c1SCatalin Marinas break; 74908e875c1SCatalin Marinas } 75045ed695aSNicolas Pitre 75145ed695aSNicolas Pitre if ((unsigned)ipinr < NR_IPI) 752be081d9bSStephen Boyd trace_ipi_exit_rcuidle(ipi_types[ipinr]); 75308e875c1SCatalin Marinas set_irq_regs(old_regs); 75408e875c1SCatalin Marinas } 75508e875c1SCatalin Marinas 75608e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 75708e875c1SCatalin Marinas { 75808e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 75908e875c1SCatalin Marinas } 76008e875c1SCatalin Marinas 7611f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 7621f85008eSLorenzo Pieralisi void tick_broadcast(const struct cpumask *mask) 7631f85008eSLorenzo Pieralisi { 7641f85008eSLorenzo Pieralisi smp_cross_call(mask, IPI_TIMER); 7651f85008eSLorenzo Pieralisi } 7661f85008eSLorenzo Pieralisi #endif 7671f85008eSLorenzo Pieralisi 76808e875c1SCatalin Marinas void smp_send_stop(void) 76908e875c1SCatalin Marinas { 77008e875c1SCatalin Marinas unsigned long timeout; 77108e875c1SCatalin Marinas 77208e875c1SCatalin Marinas if (num_online_cpus() > 1) { 77308e875c1SCatalin Marinas cpumask_t mask; 77408e875c1SCatalin Marinas 77508e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 776434ed7f4SRusty Russell cpumask_clear_cpu(smp_processor_id(), &mask); 77708e875c1SCatalin Marinas 77808e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 77908e875c1SCatalin Marinas } 78008e875c1SCatalin Marinas 78108e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 78208e875c1SCatalin Marinas timeout = USEC_PER_SEC; 78308e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 78408e875c1SCatalin Marinas udelay(1); 78508e875c1SCatalin Marinas 78608e875c1SCatalin Marinas if (num_online_cpus() > 1) 78708e875c1SCatalin Marinas pr_warning("SMP: failed to stop secondary CPUs\n"); 78808e875c1SCatalin Marinas } 78908e875c1SCatalin Marinas 79008e875c1SCatalin Marinas /* 79108e875c1SCatalin Marinas * not supported here 79208e875c1SCatalin Marinas */ 79308e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 79408e875c1SCatalin Marinas { 79508e875c1SCatalin Marinas return -EINVAL; 79608e875c1SCatalin Marinas } 797