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, 641f85008eSLorenzo Pieralisi IPI_TIMER, 6508e875c1SCatalin Marinas }; 6608e875c1SCatalin Marinas 6708e875c1SCatalin Marinas /* 6808e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 6908e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 7008e875c1SCatalin Marinas */ 71b8c6453aSPaul Gortmaker static int boot_secondary(unsigned int cpu, struct task_struct *idle) 7208e875c1SCatalin Marinas { 73652af899SMark Rutland if (cpu_ops[cpu]->cpu_boot) 74652af899SMark Rutland return cpu_ops[cpu]->cpu_boot(cpu); 7508e875c1SCatalin Marinas 76652af899SMark Rutland return -EOPNOTSUPP; 7708e875c1SCatalin Marinas } 7808e875c1SCatalin Marinas 7908e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 8008e875c1SCatalin Marinas 81b8c6453aSPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *idle) 8208e875c1SCatalin Marinas { 8308e875c1SCatalin Marinas int ret; 8408e875c1SCatalin Marinas 8508e875c1SCatalin Marinas /* 8608e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 8708e875c1SCatalin Marinas * page tables. 8808e875c1SCatalin Marinas */ 8908e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 9008e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 9108e875c1SCatalin Marinas 9208e875c1SCatalin Marinas /* 9308e875c1SCatalin Marinas * Now bring the CPU into our world. 9408e875c1SCatalin Marinas */ 9508e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 9608e875c1SCatalin Marinas if (ret == 0) { 9708e875c1SCatalin Marinas /* 9808e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 9908e875c1SCatalin Marinas * time out. 10008e875c1SCatalin Marinas */ 10108e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 10208e875c1SCatalin Marinas msecs_to_jiffies(1000)); 10308e875c1SCatalin Marinas 10408e875c1SCatalin Marinas if (!cpu_online(cpu)) { 10508e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 10608e875c1SCatalin Marinas ret = -EIO; 10708e875c1SCatalin Marinas } 10808e875c1SCatalin Marinas } else { 10908e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 11008e875c1SCatalin Marinas } 11108e875c1SCatalin Marinas 11208e875c1SCatalin Marinas secondary_data.stack = NULL; 11308e875c1SCatalin Marinas 11408e875c1SCatalin Marinas return ret; 11508e875c1SCatalin Marinas } 11608e875c1SCatalin Marinas 117*f6e763b9SMark Brown static void smp_store_cpu_info(unsigned int cpuid) 118*f6e763b9SMark Brown { 119*f6e763b9SMark Brown store_cpu_topology(cpuid); 120*f6e763b9SMark Brown } 121*f6e763b9SMark Brown 12208e875c1SCatalin Marinas /* 12308e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 12408e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 12508e875c1SCatalin Marinas */ 126b8c6453aSPaul Gortmaker asmlinkage void secondary_start_kernel(void) 12708e875c1SCatalin Marinas { 12808e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 12908e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 13008e875c1SCatalin Marinas 13108e875c1SCatalin Marinas /* 13208e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 13308e875c1SCatalin Marinas * reference and switch to it. 13408e875c1SCatalin Marinas */ 13508e875c1SCatalin Marinas atomic_inc(&mm->mm_count); 13608e875c1SCatalin Marinas current->active_mm = mm; 13708e875c1SCatalin Marinas cpumask_set_cpu(cpu, mm_cpumask(mm)); 13808e875c1SCatalin Marinas 13971586276SWill Deacon set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 14071586276SWill Deacon printk("CPU%u: Booted secondary processor\n", cpu); 14171586276SWill Deacon 14208e875c1SCatalin Marinas /* 14308e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 14408e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 14508e875c1SCatalin Marinas */ 14608e875c1SCatalin Marinas cpu_set_reserved_ttbr0(); 14708e875c1SCatalin Marinas flush_tlb_all(); 14808e875c1SCatalin Marinas 14908e875c1SCatalin Marinas preempt_disable(); 15008e875c1SCatalin Marinas trace_hardirqs_off(); 15108e875c1SCatalin Marinas 152652af899SMark Rutland if (cpu_ops[cpu]->cpu_postboot) 153652af899SMark Rutland cpu_ops[cpu]->cpu_postboot(); 15408e875c1SCatalin Marinas 15508e875c1SCatalin Marinas /* 1567ade67b5SMarc Zyngier * Enable GIC and timers. 1577ade67b5SMarc Zyngier */ 1587ade67b5SMarc Zyngier notify_cpu_starting(cpu); 1597ade67b5SMarc Zyngier 160*f6e763b9SMark Brown smp_store_cpu_info(cpu); 161*f6e763b9SMark Brown 1627ade67b5SMarc Zyngier /* 16308e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 16408e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 16508e875c1SCatalin Marinas * before we continue. 16608e875c1SCatalin Marinas */ 16708e875c1SCatalin Marinas set_cpu_online(cpu, true); 168b3770b32SWill Deacon complete(&cpu_running); 16908e875c1SCatalin Marinas 170d8ed442aSVijaya Kumar K local_dbg_enable(); 17153ae3acdSCatalin Marinas local_irq_enable(); 172b3bf6aa7SCatalin Marinas local_async_enable(); 17353ae3acdSCatalin Marinas 17453ae3acdSCatalin Marinas /* 17508e875c1SCatalin Marinas * OK, it's off to the idle thread for us 17608e875c1SCatalin Marinas */ 1770087298fSThomas Gleixner cpu_startup_entry(CPUHP_ONLINE); 17808e875c1SCatalin Marinas } 17908e875c1SCatalin Marinas 1809327e2c6SMark Rutland #ifdef CONFIG_HOTPLUG_CPU 1819327e2c6SMark Rutland static int op_cpu_disable(unsigned int cpu) 1829327e2c6SMark Rutland { 1839327e2c6SMark Rutland /* 1849327e2c6SMark Rutland * If we don't have a cpu_die method, abort before we reach the point 1859327e2c6SMark Rutland * of no return. CPU0 may not have an cpu_ops, so test for it. 1869327e2c6SMark Rutland */ 1879327e2c6SMark Rutland if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) 1889327e2c6SMark Rutland return -EOPNOTSUPP; 1899327e2c6SMark Rutland 1909327e2c6SMark Rutland /* 1919327e2c6SMark Rutland * We may need to abort a hot unplug for some other mechanism-specific 1929327e2c6SMark Rutland * reason. 1939327e2c6SMark Rutland */ 1949327e2c6SMark Rutland if (cpu_ops[cpu]->cpu_disable) 1959327e2c6SMark Rutland return cpu_ops[cpu]->cpu_disable(cpu); 1969327e2c6SMark Rutland 1979327e2c6SMark Rutland return 0; 1989327e2c6SMark Rutland } 1999327e2c6SMark Rutland 2009327e2c6SMark Rutland /* 2019327e2c6SMark Rutland * __cpu_disable runs on the processor to be shutdown. 2029327e2c6SMark Rutland */ 2039327e2c6SMark Rutland int __cpu_disable(void) 2049327e2c6SMark Rutland { 2059327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 2069327e2c6SMark Rutland int ret; 2079327e2c6SMark Rutland 2089327e2c6SMark Rutland ret = op_cpu_disable(cpu); 2099327e2c6SMark Rutland if (ret) 2109327e2c6SMark Rutland return ret; 2119327e2c6SMark Rutland 2129327e2c6SMark Rutland /* 2139327e2c6SMark Rutland * Take this CPU offline. Once we clear this, we can't return, 2149327e2c6SMark Rutland * and we must not schedule until we're ready to give up the cpu. 2159327e2c6SMark Rutland */ 2169327e2c6SMark Rutland set_cpu_online(cpu, false); 2179327e2c6SMark Rutland 2189327e2c6SMark Rutland /* 2199327e2c6SMark Rutland * OK - migrate IRQs away from this CPU 2209327e2c6SMark Rutland */ 2219327e2c6SMark Rutland migrate_irqs(); 2229327e2c6SMark Rutland 2239327e2c6SMark Rutland /* 2249327e2c6SMark Rutland * Remove this CPU from the vm mask set of all processes. 2259327e2c6SMark Rutland */ 2269327e2c6SMark Rutland clear_tasks_mm_cpumask(cpu); 2279327e2c6SMark Rutland 2289327e2c6SMark Rutland return 0; 2299327e2c6SMark Rutland } 2309327e2c6SMark Rutland 2319327e2c6SMark Rutland static DECLARE_COMPLETION(cpu_died); 2329327e2c6SMark Rutland 2339327e2c6SMark Rutland /* 2349327e2c6SMark Rutland * called on the thread which is asking for a CPU to be shutdown - 2359327e2c6SMark Rutland * waits until shutdown has completed, or it is timed out. 2369327e2c6SMark Rutland */ 2379327e2c6SMark Rutland void __cpu_die(unsigned int cpu) 2389327e2c6SMark Rutland { 2399327e2c6SMark Rutland if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { 2409327e2c6SMark Rutland pr_crit("CPU%u: cpu didn't die\n", cpu); 2419327e2c6SMark Rutland return; 2429327e2c6SMark Rutland } 2439327e2c6SMark Rutland pr_notice("CPU%u: shutdown\n", cpu); 2449327e2c6SMark Rutland } 2459327e2c6SMark Rutland 2469327e2c6SMark Rutland /* 2479327e2c6SMark Rutland * Called from the idle thread for the CPU which has been shutdown. 2489327e2c6SMark Rutland * 2499327e2c6SMark Rutland * Note that we disable IRQs here, but do not re-enable them 2509327e2c6SMark Rutland * before returning to the caller. This is also the behaviour 2519327e2c6SMark Rutland * of the other hotplug-cpu capable cores, so presumably coming 2529327e2c6SMark Rutland * out of idle fixes this. 2539327e2c6SMark Rutland */ 2549327e2c6SMark Rutland void cpu_die(void) 2559327e2c6SMark Rutland { 2569327e2c6SMark Rutland unsigned int cpu = smp_processor_id(); 2579327e2c6SMark Rutland 2589327e2c6SMark Rutland idle_task_exit(); 2599327e2c6SMark Rutland 2609327e2c6SMark Rutland local_irq_disable(); 2619327e2c6SMark Rutland 2629327e2c6SMark Rutland /* Tell __cpu_die() that this CPU is now safe to dispose of */ 2639327e2c6SMark Rutland complete(&cpu_died); 2649327e2c6SMark Rutland 2659327e2c6SMark Rutland /* 2669327e2c6SMark Rutland * Actually shutdown the CPU. This must never fail. The specific hotplug 2679327e2c6SMark Rutland * mechanism must perform all required cache maintenance to ensure that 2689327e2c6SMark Rutland * no dirty lines are lost in the process of shutting down the CPU. 2699327e2c6SMark Rutland */ 2709327e2c6SMark Rutland cpu_ops[cpu]->cpu_die(cpu); 2719327e2c6SMark Rutland 2729327e2c6SMark Rutland BUG(); 2739327e2c6SMark Rutland } 2749327e2c6SMark Rutland #endif 2759327e2c6SMark Rutland 27608e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 27708e875c1SCatalin Marinas { 278326b16dbSWill Deacon pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); 27908e875c1SCatalin Marinas } 28008e875c1SCatalin Marinas 28108e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 28208e875c1SCatalin Marinas { 28371586276SWill Deacon set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 28408e875c1SCatalin Marinas } 28508e875c1SCatalin Marinas 28608e875c1SCatalin Marinas static void (*smp_cross_call)(const struct cpumask *, unsigned int); 287d329de3fSMarc Zyngier 28808e875c1SCatalin Marinas /* 2894c7aa002SJavi Merino * Enumerate the possible CPU set from the device tree and build the 2904c7aa002SJavi Merino * cpu logical map array containing MPIDR values related to logical 2914c7aa002SJavi Merino * cpus. Assumes that cpu_logical_map(0) has already been initialized. 29208e875c1SCatalin Marinas */ 29308e875c1SCatalin Marinas void __init smp_init_cpus(void) 29408e875c1SCatalin Marinas { 29508e875c1SCatalin Marinas struct device_node *dn = NULL; 296cd1aebf5SMark Rutland unsigned int i, cpu = 1; 2974c7aa002SJavi Merino bool bootcpu_valid = false; 29808e875c1SCatalin Marinas 29908e875c1SCatalin Marinas while ((dn = of_find_node_by_type(dn, "cpu"))) { 30072aea393SWill Deacon const u32 *cell; 3014c7aa002SJavi Merino u64 hwid; 3024c7aa002SJavi Merino 3034c7aa002SJavi Merino /* 3044c7aa002SJavi Merino * A cpu node with missing "reg" property is 3054c7aa002SJavi Merino * considered invalid to build a cpu_logical_map 3064c7aa002SJavi Merino * entry. 3074c7aa002SJavi Merino */ 30872aea393SWill Deacon cell = of_get_property(dn, "reg", NULL); 30972aea393SWill Deacon if (!cell) { 3104c7aa002SJavi Merino pr_err("%s: missing reg property\n", dn->full_name); 3114c7aa002SJavi Merino goto next; 3124c7aa002SJavi Merino } 31372aea393SWill Deacon hwid = of_read_number(cell, of_n_addr_cells(dn)); 3144c7aa002SJavi Merino 3154c7aa002SJavi Merino /* 3164c7aa002SJavi Merino * Non affinity bits must be set to 0 in the DT 3174c7aa002SJavi Merino */ 3184c7aa002SJavi Merino if (hwid & ~MPIDR_HWID_BITMASK) { 3194c7aa002SJavi Merino pr_err("%s: invalid reg property\n", dn->full_name); 3204c7aa002SJavi Merino goto next; 3214c7aa002SJavi Merino } 3224c7aa002SJavi Merino 3234c7aa002SJavi Merino /* 3244c7aa002SJavi Merino * Duplicate MPIDRs are a recipe for disaster. Scan 3254c7aa002SJavi Merino * all initialized entries and check for 3264c7aa002SJavi Merino * duplicates. If any is found just ignore the cpu. 3274c7aa002SJavi Merino * cpu_logical_map was initialized to INVALID_HWID to 3284c7aa002SJavi Merino * avoid matching valid MPIDR values. 3294c7aa002SJavi Merino */ 3304c7aa002SJavi Merino for (i = 1; (i < cpu) && (i < NR_CPUS); i++) { 3314c7aa002SJavi Merino if (cpu_logical_map(i) == hwid) { 3324c7aa002SJavi Merino pr_err("%s: duplicate cpu reg properties in the DT\n", 3334c7aa002SJavi Merino dn->full_name); 3344c7aa002SJavi Merino goto next; 3354c7aa002SJavi Merino } 3364c7aa002SJavi Merino } 3374c7aa002SJavi Merino 3384c7aa002SJavi Merino /* 3394c7aa002SJavi Merino * The numbering scheme requires that the boot CPU 3404c7aa002SJavi Merino * must be assigned logical id 0. Record it so that 3414c7aa002SJavi Merino * the logical map built from DT is validated and can 3424c7aa002SJavi Merino * be used. 3434c7aa002SJavi Merino */ 3444c7aa002SJavi Merino if (hwid == cpu_logical_map(0)) { 3454c7aa002SJavi Merino if (bootcpu_valid) { 3464c7aa002SJavi Merino pr_err("%s: duplicate boot cpu reg property in DT\n", 3474c7aa002SJavi Merino dn->full_name); 3484c7aa002SJavi Merino goto next; 3494c7aa002SJavi Merino } 3504c7aa002SJavi Merino 3514c7aa002SJavi Merino bootcpu_valid = true; 3524c7aa002SJavi Merino 3534c7aa002SJavi Merino /* 3544c7aa002SJavi Merino * cpu_logical_map has already been 3554c7aa002SJavi Merino * initialized and the boot cpu doesn't need 3564c7aa002SJavi Merino * the enable-method so continue without 3574c7aa002SJavi Merino * incrementing cpu. 3584c7aa002SJavi Merino */ 3594c7aa002SJavi Merino continue; 3604c7aa002SJavi Merino } 3614c7aa002SJavi Merino 36208e875c1SCatalin Marinas if (cpu >= NR_CPUS) 36308e875c1SCatalin Marinas goto next; 36408e875c1SCatalin Marinas 365e8765b26SMark Rutland if (cpu_read_ops(dn, cpu) != 0) 366d329de3fSMarc Zyngier goto next; 36708e875c1SCatalin Marinas 368cd1aebf5SMark Rutland if (cpu_ops[cpu]->cpu_init(dn, cpu)) 36908e875c1SCatalin Marinas goto next; 37008e875c1SCatalin Marinas 3714c7aa002SJavi Merino pr_debug("cpu logical map 0x%llx\n", hwid); 3724c7aa002SJavi Merino cpu_logical_map(cpu) = hwid; 37308e875c1SCatalin Marinas next: 37408e875c1SCatalin Marinas cpu++; 37508e875c1SCatalin Marinas } 37608e875c1SCatalin Marinas 37708e875c1SCatalin Marinas /* sanity check */ 37808e875c1SCatalin Marinas if (cpu > NR_CPUS) 37908e875c1SCatalin Marinas pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n", 38008e875c1SCatalin Marinas cpu, NR_CPUS); 3814c7aa002SJavi Merino 3824c7aa002SJavi Merino if (!bootcpu_valid) { 3834c7aa002SJavi Merino pr_err("DT missing boot CPU MPIDR, not enabling secondaries\n"); 3844c7aa002SJavi Merino return; 3854c7aa002SJavi Merino } 3864c7aa002SJavi Merino 3874c7aa002SJavi Merino /* 3884c7aa002SJavi Merino * All the cpus that made it to the cpu_logical_map have been 3894c7aa002SJavi Merino * validated so set them as possible cpus. 3904c7aa002SJavi Merino */ 3914c7aa002SJavi Merino for (i = 0; i < NR_CPUS; i++) 3924c7aa002SJavi Merino if (cpu_logical_map(i) != INVALID_HWID) 3934c7aa002SJavi Merino set_cpu_possible(i, true); 39408e875c1SCatalin Marinas } 39508e875c1SCatalin Marinas 39608e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 39708e875c1SCatalin Marinas { 398cd1aebf5SMark Rutland int err; 399cd1aebf5SMark Rutland unsigned int cpu, ncores = num_possible_cpus(); 40008e875c1SCatalin Marinas 401*f6e763b9SMark Brown init_cpu_topology(); 402*f6e763b9SMark Brown 403*f6e763b9SMark Brown smp_store_cpu_info(smp_processor_id()); 404*f6e763b9SMark Brown 40508e875c1SCatalin Marinas /* 40608e875c1SCatalin Marinas * are we trying to boot more cores than exist? 40708e875c1SCatalin Marinas */ 40808e875c1SCatalin Marinas if (max_cpus > ncores) 40908e875c1SCatalin Marinas max_cpus = ncores; 41008e875c1SCatalin Marinas 411d329de3fSMarc Zyngier /* Don't bother if we're effectively UP */ 412d329de3fSMarc Zyngier if (max_cpus <= 1) 413d329de3fSMarc Zyngier return; 414d329de3fSMarc Zyngier 41508e875c1SCatalin Marinas /* 41608e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 41708e875c1SCatalin Marinas * actually populated at the present time) and release the 41808e875c1SCatalin Marinas * secondaries from the bootloader. 419d329de3fSMarc Zyngier * 420d329de3fSMarc Zyngier * Make sure we online at most (max_cpus - 1) additional CPUs. 42108e875c1SCatalin Marinas */ 422d329de3fSMarc Zyngier max_cpus--; 42308e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 42408e875c1SCatalin Marinas if (max_cpus == 0) 42508e875c1SCatalin Marinas break; 42608e875c1SCatalin Marinas 427d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 42808e875c1SCatalin Marinas continue; 42908e875c1SCatalin Marinas 430cd1aebf5SMark Rutland if (!cpu_ops[cpu]) 431d329de3fSMarc Zyngier continue; 432d329de3fSMarc Zyngier 433cd1aebf5SMark Rutland err = cpu_ops[cpu]->cpu_prepare(cpu); 434d329de3fSMarc Zyngier if (err) 435d329de3fSMarc Zyngier continue; 43608e875c1SCatalin Marinas 43708e875c1SCatalin Marinas set_cpu_present(cpu, true); 43808e875c1SCatalin Marinas max_cpus--; 43908e875c1SCatalin Marinas } 44008e875c1SCatalin Marinas } 44108e875c1SCatalin Marinas 44208e875c1SCatalin Marinas 44308e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 44408e875c1SCatalin Marinas { 44508e875c1SCatalin Marinas smp_cross_call = fn; 44608e875c1SCatalin Marinas } 44708e875c1SCatalin Marinas 44808e875c1SCatalin Marinas void arch_send_call_function_ipi_mask(const struct cpumask *mask) 44908e875c1SCatalin Marinas { 45008e875c1SCatalin Marinas smp_cross_call(mask, IPI_CALL_FUNC); 45108e875c1SCatalin Marinas } 45208e875c1SCatalin Marinas 45308e875c1SCatalin Marinas void arch_send_call_function_single_ipi(int cpu) 45408e875c1SCatalin Marinas { 45508e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 45608e875c1SCatalin Marinas } 45708e875c1SCatalin Marinas 45808e875c1SCatalin Marinas static const char *ipi_types[NR_IPI] = { 45908e875c1SCatalin Marinas #define S(x,s) [x - IPI_RESCHEDULE] = s 46008e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 46108e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 46208e875c1SCatalin Marinas S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 46308e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 4641f85008eSLorenzo Pieralisi S(IPI_TIMER, "Timer broadcast interrupts"), 46508e875c1SCatalin Marinas }; 46608e875c1SCatalin Marinas 46708e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 46808e875c1SCatalin Marinas { 46908e875c1SCatalin Marinas unsigned int cpu, i; 47008e875c1SCatalin Marinas 47108e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 47208e875c1SCatalin Marinas seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE, 47308e875c1SCatalin Marinas prec >= 4 ? " " : ""); 47467317c26SSudeep KarkadaNagesha for_each_online_cpu(cpu) 47508e875c1SCatalin Marinas seq_printf(p, "%10u ", 47608e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 47708e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 47808e875c1SCatalin Marinas } 47908e875c1SCatalin Marinas } 48008e875c1SCatalin Marinas 48108e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 48208e875c1SCatalin Marinas { 48308e875c1SCatalin Marinas u64 sum = 0; 48408e875c1SCatalin Marinas int i; 48508e875c1SCatalin Marinas 48608e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 48708e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 48808e875c1SCatalin Marinas 48908e875c1SCatalin Marinas return sum; 49008e875c1SCatalin Marinas } 49108e875c1SCatalin Marinas 49208e875c1SCatalin Marinas static DEFINE_RAW_SPINLOCK(stop_lock); 49308e875c1SCatalin Marinas 49408e875c1SCatalin Marinas /* 49508e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 49608e875c1SCatalin Marinas */ 49708e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 49808e875c1SCatalin Marinas { 49908e875c1SCatalin Marinas if (system_state == SYSTEM_BOOTING || 50008e875c1SCatalin Marinas system_state == SYSTEM_RUNNING) { 50108e875c1SCatalin Marinas raw_spin_lock(&stop_lock); 50208e875c1SCatalin Marinas pr_crit("CPU%u: stopping\n", cpu); 50308e875c1SCatalin Marinas dump_stack(); 50408e875c1SCatalin Marinas raw_spin_unlock(&stop_lock); 50508e875c1SCatalin Marinas } 50608e875c1SCatalin Marinas 50708e875c1SCatalin Marinas set_cpu_online(cpu, false); 50808e875c1SCatalin Marinas 50908e875c1SCatalin Marinas local_irq_disable(); 51008e875c1SCatalin Marinas 51108e875c1SCatalin Marinas while (1) 51208e875c1SCatalin Marinas cpu_relax(); 51308e875c1SCatalin Marinas } 51408e875c1SCatalin Marinas 51508e875c1SCatalin Marinas /* 51608e875c1SCatalin Marinas * Main handler for inter-processor interrupts 51708e875c1SCatalin Marinas */ 51808e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 51908e875c1SCatalin Marinas { 52008e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 52108e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 52208e875c1SCatalin Marinas 52308e875c1SCatalin Marinas if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI) 52408e875c1SCatalin Marinas __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]); 52508e875c1SCatalin Marinas 52608e875c1SCatalin Marinas switch (ipinr) { 52708e875c1SCatalin Marinas case IPI_RESCHEDULE: 52808e875c1SCatalin Marinas scheduler_ipi(); 52908e875c1SCatalin Marinas break; 53008e875c1SCatalin Marinas 53108e875c1SCatalin Marinas case IPI_CALL_FUNC: 53208e875c1SCatalin Marinas irq_enter(); 53308e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 53408e875c1SCatalin Marinas irq_exit(); 53508e875c1SCatalin Marinas break; 53608e875c1SCatalin Marinas 53708e875c1SCatalin Marinas case IPI_CALL_FUNC_SINGLE: 53808e875c1SCatalin Marinas irq_enter(); 53908e875c1SCatalin Marinas generic_smp_call_function_single_interrupt(); 54008e875c1SCatalin Marinas irq_exit(); 54108e875c1SCatalin Marinas break; 54208e875c1SCatalin Marinas 54308e875c1SCatalin Marinas case IPI_CPU_STOP: 54408e875c1SCatalin Marinas irq_enter(); 54508e875c1SCatalin Marinas ipi_cpu_stop(cpu); 54608e875c1SCatalin Marinas irq_exit(); 54708e875c1SCatalin Marinas break; 54808e875c1SCatalin Marinas 5491f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 5501f85008eSLorenzo Pieralisi case IPI_TIMER: 5511f85008eSLorenzo Pieralisi irq_enter(); 5521f85008eSLorenzo Pieralisi tick_receive_broadcast(); 5531f85008eSLorenzo Pieralisi irq_exit(); 5541f85008eSLorenzo Pieralisi break; 5551f85008eSLorenzo Pieralisi #endif 5561f85008eSLorenzo Pieralisi 55708e875c1SCatalin Marinas default: 55808e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 55908e875c1SCatalin Marinas break; 56008e875c1SCatalin Marinas } 56108e875c1SCatalin Marinas set_irq_regs(old_regs); 56208e875c1SCatalin Marinas } 56308e875c1SCatalin Marinas 56408e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 56508e875c1SCatalin Marinas { 56608e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 56708e875c1SCatalin Marinas } 56808e875c1SCatalin Marinas 5691f85008eSLorenzo Pieralisi #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 5701f85008eSLorenzo Pieralisi void tick_broadcast(const struct cpumask *mask) 5711f85008eSLorenzo Pieralisi { 5721f85008eSLorenzo Pieralisi smp_cross_call(mask, IPI_TIMER); 5731f85008eSLorenzo Pieralisi } 5741f85008eSLorenzo Pieralisi #endif 5751f85008eSLorenzo Pieralisi 57608e875c1SCatalin Marinas void smp_send_stop(void) 57708e875c1SCatalin Marinas { 57808e875c1SCatalin Marinas unsigned long timeout; 57908e875c1SCatalin Marinas 58008e875c1SCatalin Marinas if (num_online_cpus() > 1) { 58108e875c1SCatalin Marinas cpumask_t mask; 58208e875c1SCatalin Marinas 58308e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 58408e875c1SCatalin Marinas cpu_clear(smp_processor_id(), mask); 58508e875c1SCatalin Marinas 58608e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 58708e875c1SCatalin Marinas } 58808e875c1SCatalin Marinas 58908e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 59008e875c1SCatalin Marinas timeout = USEC_PER_SEC; 59108e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 59208e875c1SCatalin Marinas udelay(1); 59308e875c1SCatalin Marinas 59408e875c1SCatalin Marinas if (num_online_cpus() > 1) 59508e875c1SCatalin Marinas pr_warning("SMP: failed to stop secondary CPUs\n"); 59608e875c1SCatalin Marinas } 59708e875c1SCatalin Marinas 59808e875c1SCatalin Marinas /* 59908e875c1SCatalin Marinas * not supported here 60008e875c1SCatalin Marinas */ 60108e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 60208e875c1SCatalin Marinas { 60308e875c1SCatalin Marinas return -EINVAL; 60408e875c1SCatalin Marinas } 605