10462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King/* 20462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * linux/arch/arm/plat-versatile/platsmp.c 30462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * 40462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Copyright (C) 2002 ARM Ltd. 50462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * All Rights Reserved 60462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * 70462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * This program is free software; you can redistribute it and/or modify 80462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * it under the terms of the GNU General Public License version 2 as 90462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * published by the Free Software Foundation. 100462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 110462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/init.h> 120462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/errno.h> 130462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/delay.h> 140462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/device.h> 150462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/jiffies.h> 160462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/smp.h> 170462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 180462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <asm/cacheflush.h> 19eb50439b92b6298bf209a982f295ba9c0f7cb30bWill Deacon#include <asm/smp_plat.h> 200462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 210462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King/* 220462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Write pen_release in a way that is guaranteed to be visible to all 230462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * observers, irrespective of whether they're taking part in coherency 240462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * or not. This is necessary for the hotplug code to work reliably. 250462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 268bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakerstatic void write_pen_release(int val) 270462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{ 280462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King pen_release = val; 290462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King smp_wmb(); 30f45913fde00f13f502730809d128e607da2a57c8Nicolas Pitre sync_cache_w(&pen_release); 310462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King} 320462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 330462b4477ea3260304bbcd97c64c0b704b4f0f85Russell Kingstatic DEFINE_SPINLOCK(boot_lock); 340462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 358bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakervoid versatile_secondary_init(unsigned int cpu) 360462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{ 370462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 380462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * let the primary processor know we're out of the 390462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * pen, then head off into the C entry point 400462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 410462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King write_pen_release(-1); 420462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 430462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 440462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Synchronise with the boot thread. 450462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 460462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King spin_lock(&boot_lock); 470462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King spin_unlock(&boot_lock); 480462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King} 490462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 508bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakerint versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) 510462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{ 520462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King unsigned long timeout; 530462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 540462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 550462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Set synchronisation state between this boot processor 560462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * and the secondary one 570462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 580462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King spin_lock(&boot_lock); 590462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 600462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 610462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * This is really belt and braces; we hold unintended secondary 620462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * CPUs in the holding pen until we're ready for them. However, 630462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * since we haven't sent them a soft interrupt, they shouldn't 640462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * be there. 650462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 664a139b64703115e41e1a4e16ebf7eb93d0a0e349Will Deacon write_pen_release(cpu_logical_map(cpu)); 670462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 680462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 690462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Send the secondary CPU a soft interrupt, thereby causing 700462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * the boot monitor to read the system wide flags register, 710462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * and branch to the address found there. 720462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 73b1cffebf1029c87e1f1984d48463ee21093a6bc7Rob Herring arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 740462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 750462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King timeout = jiffies + (1 * HZ); 760462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King while (time_before(jiffies, timeout)) { 770462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King smp_rmb(); 780462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King if (pen_release == -1) 790462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King break; 800462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 810462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King udelay(10); 820462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King } 830462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 840462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King /* 850462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * now the secondary core is starting up let it run its 860462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * calibrations, then wait for it to finish 870462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */ 880462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King spin_unlock(&boot_lock); 890462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King 900462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King return pen_release != -1 ? -ENOSYS : 0; 910462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King} 92