1/* 2 * linux/arch/arm/plat-versatile/platsmp.c 3 * 4 * Copyright (C) 2002 ARM Ltd. 5 * All Rights Reserved 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11#include <linux/init.h> 12#include <linux/errno.h> 13#include <linux/delay.h> 14#include <linux/device.h> 15#include <linux/jiffies.h> 16#include <linux/smp.h> 17 18#include <asm/cacheflush.h> 19#include <asm/smp_plat.h> 20 21#include <plat/platsmp.h> 22 23/* 24 * Write pen_release in a way that is guaranteed to be visible to all 25 * observers, irrespective of whether they're taking part in coherency 26 * or not. This is necessary for the hotplug code to work reliably. 27 */ 28static void write_pen_release(int val) 29{ 30 pen_release = val; 31 smp_wmb(); 32 sync_cache_w(&pen_release); 33} 34 35static DEFINE_SPINLOCK(boot_lock); 36 37void versatile_secondary_init(unsigned int cpu) 38{ 39 /* 40 * let the primary processor know we're out of the 41 * pen, then head off into the C entry point 42 */ 43 write_pen_release(-1); 44 45 /* 46 * Synchronise with the boot thread. 47 */ 48 spin_lock(&boot_lock); 49 spin_unlock(&boot_lock); 50} 51 52int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) 53{ 54 unsigned long timeout; 55 56 /* 57 * Set synchronisation state between this boot processor 58 * and the secondary one 59 */ 60 spin_lock(&boot_lock); 61 62 /* 63 * This is really belt and braces; we hold unintended secondary 64 * CPUs in the holding pen until we're ready for them. However, 65 * since we haven't sent them a soft interrupt, they shouldn't 66 * be there. 67 */ 68 write_pen_release(cpu_logical_map(cpu)); 69 70 /* 71 * Send the secondary CPU a soft interrupt, thereby causing 72 * the boot monitor to read the system wide flags register, 73 * and branch to the address found there. 74 */ 75 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 76 77 timeout = jiffies + (1 * HZ); 78 while (time_before(jiffies, timeout)) { 79 smp_rmb(); 80 if (pen_release == -1) 81 break; 82 83 udelay(10); 84 } 85 86 /* 87 * now the secondary core is starting up let it run its 88 * calibrations, then wait for it to finish 89 */ 90 spin_unlock(&boot_lock); 91 92 return pen_release != -1 ? -ENOSYS : 0; 93} 94