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> 4208e875c1SCatalin Marinas #include <asm/mmu_context.h> 4308e875c1SCatalin Marinas #include <asm/pgtable.h> 4408e875c1SCatalin Marinas #include <asm/pgalloc.h> 4508e875c1SCatalin Marinas #include <asm/processor.h> 4608e875c1SCatalin Marinas #include <asm/sections.h> 4708e875c1SCatalin Marinas #include <asm/tlbflush.h> 4808e875c1SCatalin Marinas #include <asm/ptrace.h> 4908e875c1SCatalin Marinas 5008e875c1SCatalin Marinas /* 5108e875c1SCatalin Marinas * as from 2.5, kernels no longer have an init_tasks structure 5208e875c1SCatalin Marinas * so we need some other way of telling a new secondary core 5308e875c1SCatalin Marinas * where to place its SVC stack 5408e875c1SCatalin Marinas */ 5508e875c1SCatalin Marinas struct secondary_data secondary_data; 5608e875c1SCatalin Marinas volatile unsigned long secondary_holding_pen_release = -1; 5708e875c1SCatalin Marinas 5808e875c1SCatalin Marinas enum ipi_msg_type { 5908e875c1SCatalin Marinas IPI_RESCHEDULE, 6008e875c1SCatalin Marinas IPI_CALL_FUNC, 6108e875c1SCatalin Marinas IPI_CALL_FUNC_SINGLE, 6208e875c1SCatalin Marinas IPI_CPU_STOP, 6308e875c1SCatalin Marinas }; 6408e875c1SCatalin Marinas 6508e875c1SCatalin Marinas static DEFINE_RAW_SPINLOCK(boot_lock); 6608e875c1SCatalin Marinas 6708e875c1SCatalin Marinas /* 6808e875c1SCatalin Marinas * Write secondary_holding_pen_release in a way that is guaranteed to be 6908e875c1SCatalin Marinas * visible to all observers, irrespective of whether they're taking part 7008e875c1SCatalin Marinas * in coherency or not. This is necessary for the hotplug code to work 7108e875c1SCatalin Marinas * reliably. 7208e875c1SCatalin Marinas */ 7308e875c1SCatalin Marinas static void __cpuinit write_pen_release(int val) 7408e875c1SCatalin Marinas { 7508e875c1SCatalin Marinas void *start = (void *)&secondary_holding_pen_release; 7608e875c1SCatalin Marinas unsigned long size = sizeof(secondary_holding_pen_release); 7708e875c1SCatalin Marinas 7808e875c1SCatalin Marinas secondary_holding_pen_release = val; 7908e875c1SCatalin Marinas __flush_dcache_area(start, size); 8008e875c1SCatalin Marinas } 8108e875c1SCatalin Marinas 8208e875c1SCatalin Marinas /* 8308e875c1SCatalin Marinas * Boot a secondary CPU, and assign it the specified idle task. 8408e875c1SCatalin Marinas * This also gives us the initial stack to use for this CPU. 8508e875c1SCatalin Marinas */ 8608e875c1SCatalin Marinas static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 8708e875c1SCatalin Marinas { 8808e875c1SCatalin Marinas unsigned long timeout; 8908e875c1SCatalin Marinas 9008e875c1SCatalin Marinas /* 9108e875c1SCatalin Marinas * Set synchronisation state between this boot processor 9208e875c1SCatalin Marinas * and the secondary one 9308e875c1SCatalin Marinas */ 9408e875c1SCatalin Marinas raw_spin_lock(&boot_lock); 9508e875c1SCatalin Marinas 9608e875c1SCatalin Marinas /* 9708e875c1SCatalin Marinas * Update the pen release flag. 9808e875c1SCatalin Marinas */ 9908e875c1SCatalin Marinas write_pen_release(cpu); 10008e875c1SCatalin Marinas 10108e875c1SCatalin Marinas /* 10208e875c1SCatalin Marinas * Send an event, causing the secondaries to read pen_release. 10308e875c1SCatalin Marinas */ 10408e875c1SCatalin Marinas sev(); 10508e875c1SCatalin Marinas 10608e875c1SCatalin Marinas timeout = jiffies + (1 * HZ); 10708e875c1SCatalin Marinas while (time_before(jiffies, timeout)) { 10808e875c1SCatalin Marinas if (secondary_holding_pen_release == -1UL) 10908e875c1SCatalin Marinas break; 11008e875c1SCatalin Marinas udelay(10); 11108e875c1SCatalin Marinas } 11208e875c1SCatalin Marinas 11308e875c1SCatalin Marinas /* 11408e875c1SCatalin Marinas * Now the secondary core is starting up let it run its 11508e875c1SCatalin Marinas * calibrations, then wait for it to finish 11608e875c1SCatalin Marinas */ 11708e875c1SCatalin Marinas raw_spin_unlock(&boot_lock); 11808e875c1SCatalin Marinas 11908e875c1SCatalin Marinas return secondary_holding_pen_release != -1 ? -ENOSYS : 0; 12008e875c1SCatalin Marinas } 12108e875c1SCatalin Marinas 12208e875c1SCatalin Marinas static DECLARE_COMPLETION(cpu_running); 12308e875c1SCatalin Marinas 12408e875c1SCatalin Marinas int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) 12508e875c1SCatalin Marinas { 12608e875c1SCatalin Marinas int ret; 12708e875c1SCatalin Marinas 12808e875c1SCatalin Marinas /* 12908e875c1SCatalin Marinas * We need to tell the secondary core where to find its stack and the 13008e875c1SCatalin Marinas * page tables. 13108e875c1SCatalin Marinas */ 13208e875c1SCatalin Marinas secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; 13308e875c1SCatalin Marinas __flush_dcache_area(&secondary_data, sizeof(secondary_data)); 13408e875c1SCatalin Marinas 13508e875c1SCatalin Marinas /* 13608e875c1SCatalin Marinas * Now bring the CPU into our world. 13708e875c1SCatalin Marinas */ 13808e875c1SCatalin Marinas ret = boot_secondary(cpu, idle); 13908e875c1SCatalin Marinas if (ret == 0) { 14008e875c1SCatalin Marinas /* 14108e875c1SCatalin Marinas * CPU was successfully started, wait for it to come online or 14208e875c1SCatalin Marinas * time out. 14308e875c1SCatalin Marinas */ 14408e875c1SCatalin Marinas wait_for_completion_timeout(&cpu_running, 14508e875c1SCatalin Marinas msecs_to_jiffies(1000)); 14608e875c1SCatalin Marinas 14708e875c1SCatalin Marinas if (!cpu_online(cpu)) { 14808e875c1SCatalin Marinas pr_crit("CPU%u: failed to come online\n", cpu); 14908e875c1SCatalin Marinas ret = -EIO; 15008e875c1SCatalin Marinas } 15108e875c1SCatalin Marinas } else { 15208e875c1SCatalin Marinas pr_err("CPU%u: failed to boot: %d\n", cpu, ret); 15308e875c1SCatalin Marinas } 15408e875c1SCatalin Marinas 15508e875c1SCatalin Marinas secondary_data.stack = NULL; 15608e875c1SCatalin Marinas 15708e875c1SCatalin Marinas return ret; 15808e875c1SCatalin Marinas } 15908e875c1SCatalin Marinas 16008e875c1SCatalin Marinas /* 16108e875c1SCatalin Marinas * This is the secondary CPU boot entry. We're using this CPUs 16208e875c1SCatalin Marinas * idle thread stack, but a set of temporary page tables. 16308e875c1SCatalin Marinas */ 16408e875c1SCatalin Marinas asmlinkage void __cpuinit secondary_start_kernel(void) 16508e875c1SCatalin Marinas { 16608e875c1SCatalin Marinas struct mm_struct *mm = &init_mm; 16708e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 16808e875c1SCatalin Marinas 16908e875c1SCatalin Marinas printk("CPU%u: Booted secondary processor\n", cpu); 17008e875c1SCatalin Marinas 17108e875c1SCatalin Marinas /* 17208e875c1SCatalin Marinas * All kernel threads share the same mm context; grab a 17308e875c1SCatalin Marinas * reference and switch to it. 17408e875c1SCatalin Marinas */ 17508e875c1SCatalin Marinas atomic_inc(&mm->mm_count); 17608e875c1SCatalin Marinas current->active_mm = mm; 17708e875c1SCatalin Marinas cpumask_set_cpu(cpu, mm_cpumask(mm)); 17808e875c1SCatalin Marinas 17908e875c1SCatalin Marinas /* 18008e875c1SCatalin Marinas * TTBR0 is only used for the identity mapping at this stage. Make it 18108e875c1SCatalin Marinas * point to zero page to avoid speculatively fetching new entries. 18208e875c1SCatalin Marinas */ 18308e875c1SCatalin Marinas cpu_set_reserved_ttbr0(); 18408e875c1SCatalin Marinas flush_tlb_all(); 18508e875c1SCatalin Marinas 18608e875c1SCatalin Marinas preempt_disable(); 18708e875c1SCatalin Marinas trace_hardirqs_off(); 18808e875c1SCatalin Marinas 18908e875c1SCatalin Marinas /* 19008e875c1SCatalin Marinas * Let the primary processor know we're out of the 19108e875c1SCatalin Marinas * pen, then head off into the C entry point 19208e875c1SCatalin Marinas */ 19308e875c1SCatalin Marinas write_pen_release(-1); 19408e875c1SCatalin Marinas 19508e875c1SCatalin Marinas /* 19608e875c1SCatalin Marinas * Synchronise with the boot thread. 19708e875c1SCatalin Marinas */ 19808e875c1SCatalin Marinas raw_spin_lock(&boot_lock); 19908e875c1SCatalin Marinas raw_spin_unlock(&boot_lock); 20008e875c1SCatalin Marinas 20108e875c1SCatalin Marinas /* 20208e875c1SCatalin Marinas * Enable local interrupts. 20308e875c1SCatalin Marinas */ 20408e875c1SCatalin Marinas notify_cpu_starting(cpu); 20508e875c1SCatalin Marinas local_irq_enable(); 20608e875c1SCatalin Marinas local_fiq_enable(); 20708e875c1SCatalin Marinas 20808e875c1SCatalin Marinas /* 20908e875c1SCatalin Marinas * OK, now it's safe to let the boot CPU continue. Wait for 21008e875c1SCatalin Marinas * the CPU migration code to notice that the CPU is online 21108e875c1SCatalin Marinas * before we continue. 21208e875c1SCatalin Marinas */ 21308e875c1SCatalin Marinas set_cpu_online(cpu, true); 214b3770b32SWill Deacon complete(&cpu_running); 21508e875c1SCatalin Marinas 21608e875c1SCatalin Marinas /* 21708e875c1SCatalin Marinas * OK, it's off to the idle thread for us 21808e875c1SCatalin Marinas */ 21908e875c1SCatalin Marinas cpu_idle(); 22008e875c1SCatalin Marinas } 22108e875c1SCatalin Marinas 22208e875c1SCatalin Marinas void __init smp_cpus_done(unsigned int max_cpus) 22308e875c1SCatalin Marinas { 22408e875c1SCatalin Marinas unsigned long bogosum = loops_per_jiffy * num_online_cpus(); 22508e875c1SCatalin Marinas 22608e875c1SCatalin Marinas pr_info("SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", 22708e875c1SCatalin Marinas num_online_cpus(), bogosum / (500000/HZ), 22808e875c1SCatalin Marinas (bogosum / (5000/HZ)) % 100); 22908e875c1SCatalin Marinas } 23008e875c1SCatalin Marinas 23108e875c1SCatalin Marinas void __init smp_prepare_boot_cpu(void) 23208e875c1SCatalin Marinas { 23308e875c1SCatalin Marinas } 23408e875c1SCatalin Marinas 23508e875c1SCatalin Marinas static void (*smp_cross_call)(const struct cpumask *, unsigned int); 236*d329de3fSMarc Zyngier 237*d329de3fSMarc Zyngier static const struct smp_enable_ops *enable_ops[] __initconst = { 238*d329de3fSMarc Zyngier &smp_spin_table_ops, 239*d329de3fSMarc Zyngier NULL, 240*d329de3fSMarc Zyngier }; 241*d329de3fSMarc Zyngier 242*d329de3fSMarc Zyngier static const struct smp_enable_ops *smp_enable_ops[NR_CPUS]; 243*d329de3fSMarc Zyngier 244*d329de3fSMarc Zyngier static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) 245*d329de3fSMarc Zyngier { 246*d329de3fSMarc Zyngier const struct smp_enable_ops *ops = enable_ops[0]; 247*d329de3fSMarc Zyngier 248*d329de3fSMarc Zyngier while (ops) { 249*d329de3fSMarc Zyngier if (!strcmp(name, ops->name)) 250*d329de3fSMarc Zyngier return ops; 251*d329de3fSMarc Zyngier 252*d329de3fSMarc Zyngier ops++; 253*d329de3fSMarc Zyngier } 254*d329de3fSMarc Zyngier 255*d329de3fSMarc Zyngier return NULL; 256*d329de3fSMarc Zyngier } 25708e875c1SCatalin Marinas 25808e875c1SCatalin Marinas /* 25908e875c1SCatalin Marinas * Enumerate the possible CPU set from the device tree. 26008e875c1SCatalin Marinas */ 26108e875c1SCatalin Marinas void __init smp_init_cpus(void) 26208e875c1SCatalin Marinas { 26308e875c1SCatalin Marinas const char *enable_method; 26408e875c1SCatalin Marinas struct device_node *dn = NULL; 26508e875c1SCatalin Marinas int cpu = 0; 26608e875c1SCatalin Marinas 26708e875c1SCatalin Marinas while ((dn = of_find_node_by_type(dn, "cpu"))) { 26808e875c1SCatalin Marinas if (cpu >= NR_CPUS) 26908e875c1SCatalin Marinas goto next; 27008e875c1SCatalin Marinas 27108e875c1SCatalin Marinas /* 27208e875c1SCatalin Marinas * We currently support only the "spin-table" enable-method. 27308e875c1SCatalin Marinas */ 27408e875c1SCatalin Marinas enable_method = of_get_property(dn, "enable-method", NULL); 275*d329de3fSMarc Zyngier if (!enable_method) { 276*d329de3fSMarc Zyngier pr_err("CPU %d: missing enable-method property\n", cpu); 277*d329de3fSMarc Zyngier goto next; 278*d329de3fSMarc Zyngier } 279*d329de3fSMarc Zyngier 280*d329de3fSMarc Zyngier smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); 281*d329de3fSMarc Zyngier 282*d329de3fSMarc Zyngier if (!smp_enable_ops[cpu]) { 283*d329de3fSMarc Zyngier pr_err("CPU %d: invalid enable-method property: %s\n", 28408e875c1SCatalin Marinas cpu, enable_method); 28508e875c1SCatalin Marinas goto next; 28608e875c1SCatalin Marinas } 28708e875c1SCatalin Marinas 288*d329de3fSMarc Zyngier if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) 28908e875c1SCatalin Marinas goto next; 29008e875c1SCatalin Marinas 29108e875c1SCatalin Marinas set_cpu_possible(cpu, true); 29208e875c1SCatalin Marinas next: 29308e875c1SCatalin Marinas cpu++; 29408e875c1SCatalin Marinas } 29508e875c1SCatalin Marinas 29608e875c1SCatalin Marinas /* sanity check */ 29708e875c1SCatalin Marinas if (cpu > NR_CPUS) 29808e875c1SCatalin Marinas pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n", 29908e875c1SCatalin Marinas cpu, NR_CPUS); 30008e875c1SCatalin Marinas } 30108e875c1SCatalin Marinas 30208e875c1SCatalin Marinas void __init smp_prepare_cpus(unsigned int max_cpus) 30308e875c1SCatalin Marinas { 304*d329de3fSMarc Zyngier int cpu, err; 30508e875c1SCatalin Marinas unsigned int ncores = num_possible_cpus(); 30608e875c1SCatalin Marinas 30708e875c1SCatalin Marinas /* 30808e875c1SCatalin Marinas * are we trying to boot more cores than exist? 30908e875c1SCatalin Marinas */ 31008e875c1SCatalin Marinas if (max_cpus > ncores) 31108e875c1SCatalin Marinas max_cpus = ncores; 31208e875c1SCatalin Marinas 313*d329de3fSMarc Zyngier /* Don't bother if we're effectively UP */ 314*d329de3fSMarc Zyngier if (max_cpus <= 1) 315*d329de3fSMarc Zyngier return; 316*d329de3fSMarc Zyngier 31708e875c1SCatalin Marinas /* 31808e875c1SCatalin Marinas * Initialise the present map (which describes the set of CPUs 31908e875c1SCatalin Marinas * actually populated at the present time) and release the 32008e875c1SCatalin Marinas * secondaries from the bootloader. 321*d329de3fSMarc Zyngier * 322*d329de3fSMarc Zyngier * Make sure we online at most (max_cpus - 1) additional CPUs. 32308e875c1SCatalin Marinas */ 324*d329de3fSMarc Zyngier max_cpus--; 32508e875c1SCatalin Marinas for_each_possible_cpu(cpu) { 32608e875c1SCatalin Marinas if (max_cpus == 0) 32708e875c1SCatalin Marinas break; 32808e875c1SCatalin Marinas 329*d329de3fSMarc Zyngier if (cpu == smp_processor_id()) 33008e875c1SCatalin Marinas continue; 33108e875c1SCatalin Marinas 332*d329de3fSMarc Zyngier if (!smp_enable_ops[cpu]) 333*d329de3fSMarc Zyngier continue; 334*d329de3fSMarc Zyngier 335*d329de3fSMarc Zyngier err = smp_enable_ops[cpu]->prepare_cpu(cpu); 336*d329de3fSMarc Zyngier if (err) 337*d329de3fSMarc Zyngier continue; 33808e875c1SCatalin Marinas 33908e875c1SCatalin Marinas set_cpu_present(cpu, true); 34008e875c1SCatalin Marinas max_cpus--; 34108e875c1SCatalin Marinas } 34208e875c1SCatalin Marinas } 34308e875c1SCatalin Marinas 34408e875c1SCatalin Marinas 34508e875c1SCatalin Marinas void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) 34608e875c1SCatalin Marinas { 34708e875c1SCatalin Marinas smp_cross_call = fn; 34808e875c1SCatalin Marinas } 34908e875c1SCatalin Marinas 35008e875c1SCatalin Marinas void arch_send_call_function_ipi_mask(const struct cpumask *mask) 35108e875c1SCatalin Marinas { 35208e875c1SCatalin Marinas smp_cross_call(mask, IPI_CALL_FUNC); 35308e875c1SCatalin Marinas } 35408e875c1SCatalin Marinas 35508e875c1SCatalin Marinas void arch_send_call_function_single_ipi(int cpu) 35608e875c1SCatalin Marinas { 35708e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 35808e875c1SCatalin Marinas } 35908e875c1SCatalin Marinas 36008e875c1SCatalin Marinas static const char *ipi_types[NR_IPI] = { 36108e875c1SCatalin Marinas #define S(x,s) [x - IPI_RESCHEDULE] = s 36208e875c1SCatalin Marinas S(IPI_RESCHEDULE, "Rescheduling interrupts"), 36308e875c1SCatalin Marinas S(IPI_CALL_FUNC, "Function call interrupts"), 36408e875c1SCatalin Marinas S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 36508e875c1SCatalin Marinas S(IPI_CPU_STOP, "CPU stop interrupts"), 36608e875c1SCatalin Marinas }; 36708e875c1SCatalin Marinas 36808e875c1SCatalin Marinas void show_ipi_list(struct seq_file *p, int prec) 36908e875c1SCatalin Marinas { 37008e875c1SCatalin Marinas unsigned int cpu, i; 37108e875c1SCatalin Marinas 37208e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) { 37308e875c1SCatalin Marinas seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE, 37408e875c1SCatalin Marinas prec >= 4 ? " " : ""); 37508e875c1SCatalin Marinas for_each_present_cpu(cpu) 37608e875c1SCatalin Marinas seq_printf(p, "%10u ", 37708e875c1SCatalin Marinas __get_irq_stat(cpu, ipi_irqs[i])); 37808e875c1SCatalin Marinas seq_printf(p, " %s\n", ipi_types[i]); 37908e875c1SCatalin Marinas } 38008e875c1SCatalin Marinas } 38108e875c1SCatalin Marinas 38208e875c1SCatalin Marinas u64 smp_irq_stat_cpu(unsigned int cpu) 38308e875c1SCatalin Marinas { 38408e875c1SCatalin Marinas u64 sum = 0; 38508e875c1SCatalin Marinas int i; 38608e875c1SCatalin Marinas 38708e875c1SCatalin Marinas for (i = 0; i < NR_IPI; i++) 38808e875c1SCatalin Marinas sum += __get_irq_stat(cpu, ipi_irqs[i]); 38908e875c1SCatalin Marinas 39008e875c1SCatalin Marinas return sum; 39108e875c1SCatalin Marinas } 39208e875c1SCatalin Marinas 39308e875c1SCatalin Marinas static DEFINE_RAW_SPINLOCK(stop_lock); 39408e875c1SCatalin Marinas 39508e875c1SCatalin Marinas /* 39608e875c1SCatalin Marinas * ipi_cpu_stop - handle IPI from smp_send_stop() 39708e875c1SCatalin Marinas */ 39808e875c1SCatalin Marinas static void ipi_cpu_stop(unsigned int cpu) 39908e875c1SCatalin Marinas { 40008e875c1SCatalin Marinas if (system_state == SYSTEM_BOOTING || 40108e875c1SCatalin Marinas system_state == SYSTEM_RUNNING) { 40208e875c1SCatalin Marinas raw_spin_lock(&stop_lock); 40308e875c1SCatalin Marinas pr_crit("CPU%u: stopping\n", cpu); 40408e875c1SCatalin Marinas dump_stack(); 40508e875c1SCatalin Marinas raw_spin_unlock(&stop_lock); 40608e875c1SCatalin Marinas } 40708e875c1SCatalin Marinas 40808e875c1SCatalin Marinas set_cpu_online(cpu, false); 40908e875c1SCatalin Marinas 41008e875c1SCatalin Marinas local_fiq_disable(); 41108e875c1SCatalin Marinas local_irq_disable(); 41208e875c1SCatalin Marinas 41308e875c1SCatalin Marinas while (1) 41408e875c1SCatalin Marinas cpu_relax(); 41508e875c1SCatalin Marinas } 41608e875c1SCatalin Marinas 41708e875c1SCatalin Marinas /* 41808e875c1SCatalin Marinas * Main handler for inter-processor interrupts 41908e875c1SCatalin Marinas */ 42008e875c1SCatalin Marinas void handle_IPI(int ipinr, struct pt_regs *regs) 42108e875c1SCatalin Marinas { 42208e875c1SCatalin Marinas unsigned int cpu = smp_processor_id(); 42308e875c1SCatalin Marinas struct pt_regs *old_regs = set_irq_regs(regs); 42408e875c1SCatalin Marinas 42508e875c1SCatalin Marinas if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI) 42608e875c1SCatalin Marinas __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]); 42708e875c1SCatalin Marinas 42808e875c1SCatalin Marinas switch (ipinr) { 42908e875c1SCatalin Marinas case IPI_RESCHEDULE: 43008e875c1SCatalin Marinas scheduler_ipi(); 43108e875c1SCatalin Marinas break; 43208e875c1SCatalin Marinas 43308e875c1SCatalin Marinas case IPI_CALL_FUNC: 43408e875c1SCatalin Marinas irq_enter(); 43508e875c1SCatalin Marinas generic_smp_call_function_interrupt(); 43608e875c1SCatalin Marinas irq_exit(); 43708e875c1SCatalin Marinas break; 43808e875c1SCatalin Marinas 43908e875c1SCatalin Marinas case IPI_CALL_FUNC_SINGLE: 44008e875c1SCatalin Marinas irq_enter(); 44108e875c1SCatalin Marinas generic_smp_call_function_single_interrupt(); 44208e875c1SCatalin Marinas irq_exit(); 44308e875c1SCatalin Marinas break; 44408e875c1SCatalin Marinas 44508e875c1SCatalin Marinas case IPI_CPU_STOP: 44608e875c1SCatalin Marinas irq_enter(); 44708e875c1SCatalin Marinas ipi_cpu_stop(cpu); 44808e875c1SCatalin Marinas irq_exit(); 44908e875c1SCatalin Marinas break; 45008e875c1SCatalin Marinas 45108e875c1SCatalin Marinas default: 45208e875c1SCatalin Marinas pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); 45308e875c1SCatalin Marinas break; 45408e875c1SCatalin Marinas } 45508e875c1SCatalin Marinas set_irq_regs(old_regs); 45608e875c1SCatalin Marinas } 45708e875c1SCatalin Marinas 45808e875c1SCatalin Marinas void smp_send_reschedule(int cpu) 45908e875c1SCatalin Marinas { 46008e875c1SCatalin Marinas smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); 46108e875c1SCatalin Marinas } 46208e875c1SCatalin Marinas 46308e875c1SCatalin Marinas void smp_send_stop(void) 46408e875c1SCatalin Marinas { 46508e875c1SCatalin Marinas unsigned long timeout; 46608e875c1SCatalin Marinas 46708e875c1SCatalin Marinas if (num_online_cpus() > 1) { 46808e875c1SCatalin Marinas cpumask_t mask; 46908e875c1SCatalin Marinas 47008e875c1SCatalin Marinas cpumask_copy(&mask, cpu_online_mask); 47108e875c1SCatalin Marinas cpu_clear(smp_processor_id(), mask); 47208e875c1SCatalin Marinas 47308e875c1SCatalin Marinas smp_cross_call(&mask, IPI_CPU_STOP); 47408e875c1SCatalin Marinas } 47508e875c1SCatalin Marinas 47608e875c1SCatalin Marinas /* Wait up to one second for other CPUs to stop */ 47708e875c1SCatalin Marinas timeout = USEC_PER_SEC; 47808e875c1SCatalin Marinas while (num_online_cpus() > 1 && timeout--) 47908e875c1SCatalin Marinas udelay(1); 48008e875c1SCatalin Marinas 48108e875c1SCatalin Marinas if (num_online_cpus() > 1) 48208e875c1SCatalin Marinas pr_warning("SMP: failed to stop secondary CPUs\n"); 48308e875c1SCatalin Marinas } 48408e875c1SCatalin Marinas 48508e875c1SCatalin Marinas /* 48608e875c1SCatalin Marinas * not supported here 48708e875c1SCatalin Marinas */ 48808e875c1SCatalin Marinas int setup_profiling_timer(unsigned int multiplier) 48908e875c1SCatalin Marinas { 49008e875c1SCatalin Marinas return -EINVAL; 49108e875c1SCatalin Marinas } 492