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 2008e875c1SCatalin Marinas #include <linux/delay.h> 2108e875c1SCatalin Marinas #include <linux/init.h> 2208e875c1SCatalin Marinas #include <linux/spinlock.h> 2308e875c1SCatalin Marinas #include <linux/sched.h> 2408e875c1SCatalin Marinas #include <linux/interrupt.h> 2508e875c1SCatalin Marinas #include <linux/cache.h> 2608e875c1SCatalin Marinas #include <linux/profile.h> 2708e875c1SCatalin Marinas #include <linux/errno.h> 2808e875c1SCatalin Marinas #include <linux/mm.h> 2908e875c1SCatalin Marinas #include <linux/err.h> 3008e875c1SCatalin Marinas #include <linux/cpu.h> 3108e875c1SCatalin Marinas #include <linux/smp.h> 3208e875c1SCatalin Marinas #include <linux/seq_file.h> 3308e875c1SCatalin Marinas #include <linux/irq.h> 3408e875c1SCatalin Marinas #include <linux/percpu.h> 3508e875c1SCatalin Marinas #include <linux/clockchips.h> 3608e875c1SCatalin Marinas #include <linux/completion.h> 3708e875c1SCatalin Marinas #include <linux/of.h> 3808e875c1SCatalin Marinas 3908e875c1SCatalin Marinas #include <asm/atomic.h> 4008e875c1SCatalin Marinas #include <asm/cacheflush.h> 4108e875c1SCatalin Marinas #include <asm/cputype.h> 42cd1aebf5SMark Rutland #include <asm/cpu_ops.h> 4308e875c1SCatalin Marinas #include <asm/mmu_context.h> 4408e875c1SCatalin Marinas #include <asm/pgtable.h> 4508e875c1SCatalin Marinas #include <asm/pgalloc.h> 4608e875c1SCatalin Marinas #include <asm/processor.h> 474c7aa002SJavi Merino #include <asm/smp_plat.h> 4808e875c1SCatalin Marinas #include <asm/sections.h> 4908e875c1SCatalin Marinas #include <asm/tlbflush.h> 5008e875c1SCatalin Marinas #include <asm/ptrace.h> 5108e875c1SCatalin Marinas 5208e875c1SCatalin Marinas /* 5308e875c1SCatalin Marinas * as from 2.5, kernels no longer have an init_tasks structure 5408e875c1SCatalin Marinas * so we need some other way of telling a new secondary core 5508e875c1SCatalin Marinas * where to place its SVC stack 5608e875c1SCatalin Marinas */ 5708e875c1SCatalin Marinas struct secondary_data secondary_data; 5808e875c1SCatalin Marinas 5908e875c1SCatalin Marinas enum ipi_msg_type { 6008e875c1SCatalin Marinas IPI_RESCHEDULE, 6108e875c1SCatalin Marinas IPI_CALL_FUNC, 6208e875c1SCatalin Marinas IPI_CALL_FUNC_SINGLE, 6308e875c1SCatalin Marinas IPI_CPU_STOP, 6408e875c1SCatalin Marinas }; 6508e875c1SCatalin Marinas 6608e875c1SCatalin Marinas /* 6708e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 6808e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 6908e875c1SCatalin Marinas */ 70b8c6453aSPaul Gortmaker static int boot_secondary(unsigned int cpu, struct task_struct *idle) 7108e875c1SCatalin Marinas { 72652af899SMark Rutland if (cpu_ops[cpu]->cpu_boot) 73652af899SMark Rutland return cpu_ops[cpu]->cpu_boot(cpu); 7408e875c1SCatalin Marinas 75652af899SMark Rutland return -EOPNOTSUPP; 7608e875c1SCatalin Marinas } 7708e875c1SCatalin Marinas 7808e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 7908e875c1SCatalin Marinas 80b8c6453aSPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *idle) 8108e875c1SCatalin Marinas { 8208e875c1SCatalin Marinas int ret; 8308e875c1SCatalin Marinas 8408e875c1SCatalin Marinas /* 8508e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 8608e875c1SCatalin Marinas * page tables. 8708e875c1SCatalin Marinas */ 8808e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 8908e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 9008e875c1SCatalin Marinas 9108e875c1SCatalin Marinas /* 9208e875c1SCatalin Marinas * Now bring the CPU into our world. 9308e875c1SCatalin Marinas */ 9408e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 9508e875c1SCatalin Marinas if (ret == 0) { 9608e875c1SCatalin Marinas /* 9708e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 9808e875c1SCatalin Marinas * time out. 9908e875c1SCatalin Marinas */ 10008e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 10108e875c1SCatalin Marinas msecs_to_jiffies(1000)); 10208e875c1SCatalin Marinas 10308e875c1SCatalin Marinas if (!cpu_online(cpu)) { 10408e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 10508e875c1SCatalin Marinas ret = -EIO; 10608e875c1SCatalin Marinas } 10708e875c1SCatalin Marinas } else { 10808e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 10908e875c1SCatalin Marinas } 11008e875c1SCatalin Marinas 11108e875c1SCatalin Marinas secondary_data.stack = NULL; 11208e875c1SCatalin Marinas 11308e875c1SCatalin Marinas return ret; 11408e875c1SCatalin Marinas } 11508e875c1SCatalin Marinas 11608e875c1SCatalin Marinas /* 11708e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 11808e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 11908e875c1SCatalin Marinas */ 120b8c6453aSPaul Gortmaker asmlinkage void secondary_start_kernel(void) 12108e875c1SCatalin Marinas { 12208e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 12308e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 12408e875c1SCatalin Marinas 12508e875c1SCatalin Marinas printk("CPU%u: Booted secondary processor\n", cpu); 12608e875c1SCatalin Marinas 12708e875c1SCatalin Marinas /* 12808e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 12908e875c1SCatalin Marinas * reference and switch to it. 13008e875c1SCatalin Marinas */ 13108e875c1SCatalin Marinas atomic_inc(&mm->mm_count); 13208e875c1SCatalin Marinas current->active_mm = mm; 13308e875c1SCatalin Marinas cpumask_set_cpu(cpu, mm_cpumask(mm)); 13408e875c1SCatalin Marinas 13508e875c1SCatalin Marinas /* 13608e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 13708e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 13808e875c1SCatalin Marinas */ 13908e875c1SCatalin Marinas cpu_set_reserved_ttbr0(); 14008e875c1SCatalin Marinas flush_tlb_all(); 14108e875c1SCatalin Marinas 14208e875c1SCatalin Marinas preempt_disable(); 14308e875c1SCatalin Marinas trace_hardirqs_off(); 14408e875c1SCatalin Marinas 145652af899SMark Rutland if (cpu_ops[cpu]->cpu_postboot) 146652af899SMark Rutland cpu_ops[cpu]->cpu_postboot(); 14708e875c1SCatalin Marinas 14808e875c1SCatalin Marinas /* 149*7ade67b5SMarc Zyngier * Enable GIC and timers. 150*7ade67b5SMarc Zyngier */ 151*7ade67b5SMarc Zyngier notify_cpu_starting(cpu); 152*7ade67b5SMarc Zyngier 153*7ade67b5SMarc Zyngier /* 15408e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 15508e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 15608e875c1SCatalin Marinas * before we continue. 15708e875c1SCatalin Marinas */ 15808e875c1SCatalin Marinas set_cpu_online(cpu, true); 159b3770b32SWill Deacon complete(&cpu_running); 16008e875c1SCatalin Marinas 16153ae3acdSCatalin Marinas local_irq_enable(); 16253ae3acdSCatalin Marinas local_fiq_enable(); 16353ae3acdSCatalin Marinas 16453ae3acdSCatalin Marinas /* 16508e875c1SCatalin Marinas * OK, it's off to the idle thread for us 16608e875c1SCatalin Marinas */ 1670087298fSThomas Gleixner cpu_startup_entry(CPUHP_ONLINE); 16808e875c1SCatalin Marinas } 16908e875c1SCatalin Marinas 1709327e2c6SMark Rutland #ifdef CONFIG_HOTPLUG_CPU 1719327e2c6SMark Rutland static int op_cpu_disable(unsigned int cpu) 1729327e2c6SMark Rutland { 1739327e2c6SMark Rutland /* 1749327e2c6SMark Rutland * If we don't have a cpu_die method, abort before we reach the point 1759327e2c6SMark Rutland * of no return. CPU0 may not have an cpu_ops, so test for it. 1769327e2c6SMark Rutland */ 1779327e2c6SMark Rutland if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) 1789327e2c6SMark Rutland return -EOPNOTSUPP; 1799327e2c6SMark Rutland 1809327e2c6SMark Rutland /* 1819327e2c6SMark Rutland * We may need to abort a hot unplug for some other mechanism-specific 1829327e2c6SMark Rutland * reason. 1839327e2c6SMark Rutland */ 1849327e2c6SMark Rutland if (cpu_ops[cpu]->cpu_disable) 1859327e2c6SMark Rutland return cpu_ops[cpu]->cpu_disable(cpu); 1869327e2c6SMark Rutland 1879327e2c6SMark Rutland return 0; 1889327e2c6SMark Rutland } 1899327e2c6SMark Rutland 1909327e2c6SMark Rutland /* 1919327e2c6SMark Rutland * __cpu_disable runs on the processor to be shutdown. 1929327e2c6SMark Rutland */ 1939327e2c6SMark Rutland int __cpu_disable(void) 1949327e2c6SMark Rutland { 1959327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 1969327e2c6SMark Rutland int ret; 1979327e2c6SMark Rutland 1989327e2c6SMark Rutland ret = op_cpu_disable(cpu); 1999327e2c6SMark Rutland if (ret) 2009327e2c6SMark Rutland return ret; 2019327e2c6SMark Rutland 2029327e2c6SMark Rutland /* 2039327e2c6SMark Rutland * Take this CPU offline. Once we clear this, we can't return, 2049327e2c6SMark Rutland * and we must not schedule until we're ready to give up the cpu. 2059327e2c6SMark Rutland */ 2069327e2c6SMark Rutland set_cpu_online(cpu, false); 2079327e2c6SMark Rutland 2089327e2c6SMark Rutland /* 2099327e2c6SMark Rutland * OK - migrate IRQs away from this CPU 2109327e2c6SMark Rutland */ 2119327e2c6SMark Rutland migrate_irqs(); 2129327e2c6SMark Rutland 2139327e2c6SMark Rutland /* 2149327e2c6SMark Rutland * Remove this CPU from the vm mask set of all processes. 2159327e2c6SMark Rutland */ 2169327e2c6SMark Rutland clear_tasks_mm_cpumask(cpu); 2179327e2c6SMark Rutland 2189327e2c6SMark Rutland return 0; 2199327e2c6SMark Rutland } 2209327e2c6SMark Rutland 2219327e2c6SMark Rutland static DECLARE_COMPLETION(cpu_died); 2229327e2c6SMark Rutland 2239327e2c6SMark Rutland /* 2249327e2c6SMark Rutland * called on the thread which is asking for a CPU to be shutdown - 2259327e2c6SMark Rutland * waits until shutdown has completed, or it is timed out. 2269327e2c6SMark Rutland */ 2279327e2c6SMark Rutland void __cpu_die(unsigned int cpu) 2289327e2c6SMark Rutland { 2299327e2c6SMark Rutland if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { 2309327e2c6SMark Rutland pr_crit("CPU%u: cpu didn't die\n", cpu); 2319327e2c6SMark Rutland return; 2329327e2c6SMark Rutland } 2339327e2c6SMark Rutland pr_notice("CPU%u: shutdown\n", cpu); 2349327e2c6SMark Rutland } 2359327e2c6SMark Rutland 2369327e2c6SMark Rutland /* 2379327e2c6SMark Rutland * Called from the idle thread for the CPU which has been shutdown. 2389327e2c6SMark Rutland * 2399327e2c6SMark Rutland * Note that we disable IRQs here, but do not re-enable them 2409327e2c6SMark Rutland * before returning to the caller. This is also the behaviour 2419327e2c6SMark Rutland * of the other hotplug-cpu capable cores, so presumably coming 2429327e2c6SMark Rutland * out of idle fixes this. 2439327e2c6SMark Rutland */ 2449327e2c6SMark Rutland void cpu_die(void) 2459327e2c6SMark Rutland { 2469327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 2479327e2c6SMark Rutland 2489327e2c6SMark Rutland idle_task_exit(); 2499327e2c6SMark Rutland 2509327e2c6SMark Rutland local_irq_disable(); 2519327e2c6SMark Rutland 2529327e2c6SMark Rutland /* Tell __cpu_die() that this CPU is now safe to dispose of */ 2539327e2c6SMark Rutland complete(&cpu_died); 2549327e2c6SMark Rutland 2559327e2c6SMark Rutland /* 2569327e2c6SMark Rutland * Actually shutdown the CPU. This must never fail. The specific hotplug 2579327e2c6SMark Rutland * mechanism must perform all required cache maintenance to ensure that 2589327e2c6SMark Rutland * no dirty lines are lost in the process of shutting down the CPU. 2599327e2c6SMark Rutland */ 2609327e2c6SMark Rutland cpu_ops[cpu]->cpu_die(cpu); 2619327e2c6SMark Rutland 2629327e2c6SMark Rutland BUG(); 2639327e2c6SMark Rutland } 2649327e2c6SMark Rutland #endif 2659327e2c6SMark Rutland 26608e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 26708e875c1SCatalin Marinas { 268326b16dbSWill Deacon pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); 26908e875c1SCatalin Marinas } 27008e875c1SCatalin Marinas 27108e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 27208e875c1SCatalin Marinas { 27308e875c1SCatalin Marinas } 27408e875c1SCatalin Marinas 27508e875c1SCatalin Marinas static void (*smp_cross_call)(const struct cpumask *, unsigned int); 276d329de3fSMarc Zyngier 27708e875c1SCatalin Marinas /* 2784c7aa002SJavi Merino * Enumerate the possible CPU set from the device tree and build the 2794c7aa002SJavi Merino * cpu logical map array containing MPIDR values related to logical 2804c7aa002SJavi Merino * cpus. Assumes that cpu_logical_map(0) has already been initialized. 28108e875c1SCatalin Marinas */ 28208e875c1SCatalin Marinas void __init smp_init_cpus(void) 28308e875c1SCatalin Marinas { 28408e875c1SCatalin Marinas struct device_node *dn = NULL; 285cd1aebf5SMark Rutland unsigned int i, cpu = 1; 2864c7aa002SJavi Merino bool bootcpu_valid = false; 28708e875c1SCatalin Marinas 28808e875c1SCatalin Marinas while ((dn = of_find_node_by_type(dn, "cpu"))) { 28972aea393SWill Deacon const u32 *cell; 2904c7aa002SJavi Merino u64 hwid; 2914c7aa002SJavi Merino 2924c7aa002SJavi Merino /* 2934c7aa002SJavi Merino * A cpu node with missing "reg" property is 2944c7aa002SJavi Merino * considered invalid to build a cpu_logical_map 2954c7aa002SJavi Merino * entry. 2964c7aa002SJavi Merino */ 29772aea393SWill Deacon cell = of_get_property(dn, "reg", NULL); 29872aea393SWill Deacon if (!cell) { 2994c7aa002SJavi Merino pr_err("%s: missing reg property\n", dn->full_name); 3004c7aa002SJavi Merino goto next; 3014c7aa002SJavi Merino } 30272aea393SWill Deacon hwid = of_read_number(cell, of_n_addr_cells(dn)); 3034c7aa002SJavi Merino 3044c7aa002SJavi Merino /* 3054c7aa002SJavi Merino * Non affinity bits must be set to 0 in the DT 3064c7aa002SJavi Merino */ 3074c7aa002SJavi Merino if (hwid & ~MPIDR_HWID_BITMASK) { 3084c7aa002SJavi Merino pr_err("%s: invalid reg property\n", dn->full_name); 3094c7aa002SJavi Merino goto next; 3104c7aa002SJavi Merino } 3114c7aa002SJavi Merino 3124c7aa002SJavi Merino /* 3134c7aa002SJavi Merino * Duplicate MPIDRs are a recipe for disaster. Scan 3144c7aa002SJavi Merino * all initialized entries and check for 3154c7aa002SJavi Merino * duplicates. If any is found just ignore the cpu. 3164c7aa002SJavi Merino * cpu_logical_map was initialized to INVALID_HWID to 3174c7aa002SJavi Merino * avoid matching valid MPIDR values. 3184c7aa002SJavi Merino */ 3194c7aa002SJavi Merino for (i = 1; (i < cpu) && (i < NR_CPUS); i++) { 3204c7aa002SJavi Merino if (cpu_logical_map(i) == hwid) { 3214c7aa002SJavi Merino pr_err("%s: duplicate cpu reg properties in the DT\n", 3224c7aa002SJavi Merino dn->full_name); 3234c7aa002SJavi Merino goto next; 3244c7aa002SJavi Merino } 3254c7aa002SJavi Merino } 3264c7aa002SJavi Merino 3274c7aa002SJavi Merino /* 3284c7aa002SJavi Merino * The numbering scheme requires that the boot CPU 3294c7aa002SJavi Merino * must be assigned logical id 0. Record it so that 3304c7aa002SJavi Merino * the logical map built from DT is validated and can 3314c7aa002SJavi Merino * be used. 3324c7aa002SJavi Merino */ 3334c7aa002SJavi Merino if (hwid == cpu_logical_map(0)) { 3344c7aa002SJavi Merino if (bootcpu_valid) { 3354c7aa002SJavi Merino pr_err("%s: duplicate boot cpu reg property in DT\n", 3364c7aa002SJavi Merino dn->full_name); 3374c7aa002SJavi Merino goto next; 3384c7aa002SJavi Merino } 3394c7aa002SJavi Merino 3404c7aa002SJavi Merino bootcpu_valid = true; 3414c7aa002SJavi Merino 3424c7aa002SJavi Merino /* 3434c7aa002SJavi Merino * cpu_logical_map has already been 3444c7aa002SJavi Merino * initialized and the boot cpu doesn't need 3454c7aa002SJavi Merino * the enable-method so continue without 3464c7aa002SJavi Merino * incrementing cpu. 3474c7aa002SJavi Merino */ 3484c7aa002SJavi Merino continue; 3494c7aa002SJavi Merino } 3504c7aa002SJavi Merino 35108e875c1SCatalin Marinas if (cpu >= NR_CPUS) 35208e875c1SCatalin Marinas goto next; 35308e875c1SCatalin Marinas 354e8765b26SMark Rutland if (cpu_read_ops(dn, cpu) != 0) 355d329de3fSMarc Zyngier goto next; 35608e875c1SCatalin Marinas 357cd1aebf5SMark Rutland if (cpu_ops[cpu]->cpu_init(dn, cpu)) 35808e875c1SCatalin Marinas goto next; 35908e875c1SCatalin Marinas 3604c7aa002SJavi Merino pr_debug("cpu logical map 0x%llx\n", hwid); 3614c7aa002SJavi Merino cpu_logical_map(cpu) = hwid; 36208e875c1SCatalin Marinas next: 36308e875c1SCatalin Marinas cpu++; 36408e875c1SCatalin Marinas } 36508e875c1SCatalin Marinas 36608e875c1SCatalin Marinas /* sanity check */ 36708e875c1SCatalin Marinas if (cpu > NR_CPUS) 36808e875c1SCatalin Marinas pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n", 36908e875c1SCatalin Marinas cpu, NR_CPUS); 3704c7aa002SJavi Merino 3714c7aa002SJavi Merino if (!bootcpu_valid) { 3724c7aa002SJavi Merino pr_err("DT missing boot CPU MPIDR, not enabling secondaries\n"); 3734c7aa002SJavi Merino return; 3744c7aa002SJavi Merino } 3754c7aa002SJavi Merino 3764c7aa002SJavi Merino /* 3774c7aa002SJavi Merino * All the cpus that made it to the cpu_logical_map have been 3784c7aa002SJavi Merino * validated so set them as possible cpus. 3794c7aa002SJavi Merino */ 3804c7aa002SJavi Merino for (i = 0; i < NR_CPUS; i++) 3814c7aa002SJavi Merino if (cpu_logical_map(i) != INVALID_HWID) 3824c7aa002SJavi Merino set_cpu_possible(i, true); 38308e875c1SCatalin Marinas } 38408e875c1SCatalin Marinas 38508e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 38608e875c1SCatalin Marinas { 387cd1aebf5SMark Rutland int err; 388cd1aebf5SMark Rutland unsigned int cpu, ncores = num_possible_cpus(); 38908e875c1SCatalin Marinas 39008e875c1SCatalin Marinas /* 39108e875c1SCatalin Marinas * are we trying to boot more cores than exist? 39208e875c1SCatalin Marinas */ 39308e875c1SCatalin Marinas if (max_cpus > ncores) 39408e875c1SCatalin Marinas max_cpus = ncores; 39508e875c1SCatalin Marinas 396d329de3fSMarc Zyngier /* Don't bother if we're effectively UP */ 397d329de3fSMarc Zyngier if (max_cpus <= 1) 398d329de3fSMarc Zyngier return; 399d329de3fSMarc Zyngier 40008e875c1SCatalin Marinas /* 40108e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 40208e875c1SCatalin Marinas * actually populated at the present time) and release the 40308e875c1SCatalin Marinas * secondaries from the bootloader. 404d329de3fSMarc Zyngier * 405d329de3fSMarc Zyngier * Make sure we online at most (max_cpus - 1) additional CPUs. 40608e875c1SCatalin Marinas */ 407d329de3fSMarc Zyngier max_cpus--; 40808e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 40908e875c1SCatalin Marinas if (max_cpus == 0) 41008e875c1SCatalin Marinas break; 41108e875c1SCatalin Marinas 412d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 41308e875c1SCatalin Marinas continue; 41408e875c1SCatalin Marinas 415cd1aebf5SMark Rutland if (!cpu_ops[cpu]) 416d329de3fSMarc Zyngier continue; 417d329de3fSMarc Zyngier 418cd1aebf5SMark Rutland err = cpu_ops[cpu]->cpu_prepare(cpu); 419d329de3fSMarc Zyngier if (err) 420d329de3fSMarc Zyngier continue; 42108e875c1SCatalin Marinas 42208e875c1SCatalin Marinas set_cpu_present(cpu, true); 42308e875c1SCatalin Marinas max_cpus--; 42408e875c1SCatalin Marinas } 42508e875c1SCatalin Marinas } 42608e875c1SCatalin Marinas 42708e875c1SCatalin Marinas 42808e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 42908e875c1SCatalin Marinas { 43008e875c1SCatalin Marinas smp_cross_call = fn; 43108e875c1SCatalin Marinas } 43208e875c1SCatalin Marinas 43308e875c1SCatalin Marinas void arch_send_call_function_ipi_mask(const struct cpumask *mask) 43408e875c1SCatalin Marinas { 43508e875c1SCatalin Marinas smp_cross_call(mask, IPI_CALL_FUNC); 43608e875c1SCatalin Marinas } 43708e875c1SCatalin Marinas 43808e875c1SCatalin Marinas void arch_send_call_function_single_ipi(int cpu) 43908e875c1SCatalin Marinas { 44008e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 44108e875c1SCatalin Marinas } 44208e875c1SCatalin Marinas 44308e875c1SCatalin Marinas static const char *ipi_types[NR_IPI] = { 44408e875c1SCatalin Marinas #define S(x,s) [x - IPI_RESCHEDULE] = s 44508e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 44608e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 44708e875c1SCatalin Marinas S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 44808e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 44908e875c1SCatalin Marinas }; 45008e875c1SCatalin Marinas 45108e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 45208e875c1SCatalin Marinas { 45308e875c1SCatalin Marinas unsigned int cpu, i; 45408e875c1SCatalin Marinas 45508e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 45608e875c1SCatalin Marinas seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE, 45708e875c1SCatalin Marinas prec >= 4 ? " " : ""); 45808e875c1SCatalin Marinas for_each_present_cpu(cpu) 45908e875c1SCatalin Marinas seq_printf(p, "%10u ", 46008e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 46108e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 46208e875c1SCatalin Marinas } 46308e875c1SCatalin Marinas } 46408e875c1SCatalin Marinas 46508e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 46608e875c1SCatalin Marinas { 46708e875c1SCatalin Marinas u64 sum = 0; 46808e875c1SCatalin Marinas int i; 46908e875c1SCatalin Marinas 47008e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 47108e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 47208e875c1SCatalin Marinas 47308e875c1SCatalin Marinas return sum; 47408e875c1SCatalin Marinas } 47508e875c1SCatalin Marinas 47608e875c1SCatalin Marinas static DEFINE_RAW_SPINLOCK(stop_lock); 47708e875c1SCatalin Marinas 47808e875c1SCatalin Marinas /* 47908e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 48008e875c1SCatalin Marinas */ 48108e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 48208e875c1SCatalin Marinas { 48308e875c1SCatalin Marinas if (system_state == SYSTEM_BOOTING || 48408e875c1SCatalin Marinas system_state == SYSTEM_RUNNING) { 48508e875c1SCatalin Marinas raw_spin_lock(&stop_lock); 48608e875c1SCatalin Marinas pr_crit("CPU%u: stopping\n", cpu); 48708e875c1SCatalin Marinas dump_stack(); 48808e875c1SCatalin Marinas raw_spin_unlock(&stop_lock); 48908e875c1SCatalin Marinas } 49008e875c1SCatalin Marinas 49108e875c1SCatalin Marinas set_cpu_online(cpu, false); 49208e875c1SCatalin Marinas 49308e875c1SCatalin Marinas local_fiq_disable(); 49408e875c1SCatalin Marinas local_irq_disable(); 49508e875c1SCatalin Marinas 49608e875c1SCatalin Marinas while (1) 49708e875c1SCatalin Marinas cpu_relax(); 49808e875c1SCatalin Marinas } 49908e875c1SCatalin Marinas 50008e875c1SCatalin Marinas /* 50108e875c1SCatalin Marinas * Main handler for inter-processor interrupts 50208e875c1SCatalin Marinas */ 50308e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 50408e875c1SCatalin Marinas { 50508e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 50608e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 50708e875c1SCatalin Marinas 50808e875c1SCatalin Marinas if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI) 50908e875c1SCatalin Marinas __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]); 51008e875c1SCatalin Marinas 51108e875c1SCatalin Marinas switch (ipinr) { 51208e875c1SCatalin Marinas case IPI_RESCHEDULE: 51308e875c1SCatalin Marinas scheduler_ipi(); 51408e875c1SCatalin Marinas break; 51508e875c1SCatalin Marinas 51608e875c1SCatalin Marinas case IPI_CALL_FUNC: 51708e875c1SCatalin Marinas irq_enter(); 51808e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 51908e875c1SCatalin Marinas irq_exit(); 52008e875c1SCatalin Marinas break; 52108e875c1SCatalin Marinas 52208e875c1SCatalin Marinas case IPI_CALL_FUNC_SINGLE: 52308e875c1SCatalin Marinas irq_enter(); 52408e875c1SCatalin Marinas generic_smp_call_function_single_interrupt(); 52508e875c1SCatalin Marinas irq_exit(); 52608e875c1SCatalin Marinas break; 52708e875c1SCatalin Marinas 52808e875c1SCatalin Marinas case IPI_CPU_STOP: 52908e875c1SCatalin Marinas irq_enter(); 53008e875c1SCatalin Marinas ipi_cpu_stop(cpu); 53108e875c1SCatalin Marinas irq_exit(); 53208e875c1SCatalin Marinas break; 53308e875c1SCatalin Marinas 53408e875c1SCatalin Marinas default: 53508e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 53608e875c1SCatalin Marinas break; 53708e875c1SCatalin Marinas } 53808e875c1SCatalin Marinas set_irq_regs(old_regs); 53908e875c1SCatalin Marinas } 54008e875c1SCatalin Marinas 54108e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 54208e875c1SCatalin Marinas { 54308e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 54408e875c1SCatalin Marinas } 54508e875c1SCatalin Marinas 54608e875c1SCatalin Marinas void smp_send_stop(void) 54708e875c1SCatalin Marinas { 54808e875c1SCatalin Marinas unsigned long timeout; 54908e875c1SCatalin Marinas 55008e875c1SCatalin Marinas if (num_online_cpus() > 1) { 55108e875c1SCatalin Marinas cpumask_t mask; 55208e875c1SCatalin Marinas 55308e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 55408e875c1SCatalin Marinas cpu_clear(smp_processor_id(), mask); 55508e875c1SCatalin Marinas 55608e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 55708e875c1SCatalin Marinas } 55808e875c1SCatalin Marinas 55908e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 56008e875c1SCatalin Marinas timeout = USEC_PER_SEC; 56108e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 56208e875c1SCatalin Marinas udelay(1); 56308e875c1SCatalin Marinas 56408e875c1SCatalin Marinas if (num_online_cpus() > 1) 56508e875c1SCatalin Marinas pr_warning("SMP: failed to stop secondary CPUs\n"); 56608e875c1SCatalin Marinas } 56708e875c1SCatalin Marinas 56808e875c1SCatalin Marinas /* 56908e875c1SCatalin Marinas * not supported here 57008e875c1SCatalin Marinas */ 57108e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 57208e875c1SCatalin Marinas { 57308e875c1SCatalin Marinas return -EINVAL; 57408e875c1SCatalin Marinas } 575