smp.c revision a123322d8afcfb5f86e0cc0062024084658aeeb2
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	linux/arch/alpha/kernel/smp.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      2001-07-09 Phil Ezolt (Phillip.Ezolt@compaq.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Renamed modified smp_call_function to smp_call_function_on_cpu()
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            Created an function that conforms to the old calling convention
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            of smp_call_function().
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            This is helpful for DCPI.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel_stat.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
194e950f6f0189f65f8bf069cf2272649ef418f5e4Alexey Dobriyan#include <linux/err.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/threads.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/irq.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cache.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/profile.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
30574f34cee2b6574d43bf4506f771c1cec6a5d391Alexey Dobriyan#include <linux/cpu.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hwrpb.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ptrace.h>
3460063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgalloc.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mmu_context.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/tlbflush.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "proto.h"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "irq_impl.h"
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_SMP 0
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_SMP
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBGS(args)	printk args
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBGS(args)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A collection of per-processor data.  */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpuinfo_alpha cpu_data[NR_CPUS];
56cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(cpu_data);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A collection of single bit ipi messages.  */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct {
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bits ____cacheline_aligned;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ipi_data[NR_CPUS] __cacheline_aligned;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum ipi_message_type {
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_RESCHEDULE,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_CALL_FUNC,
66c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe	IPI_CALL_FUNC_SINGLE,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_CPU_STOP,
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set to a secondary's cpuid when it comes online.  */
71f8d6c8d98d9ea7afef1e0d93d756a2dca879d1eaGreg Kroah-Hartmanstatic int smp_secondary_alive = 0;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_probed;		/* Internal processor count */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_cpus = 1;		/* Number that came online.  */
75cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_num_cpus);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by both boot and secondaries to move global data into
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  per-processor storage.
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_store_cpu_info(int cpuid)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].last_asn = ASN_FIRST_VERSION;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].need_new_asn = 0;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].asn_lock = 0;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_setup_percpu_timer(int cpuid)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_counter = 1;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_multiplier = 1;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_boot_cpu_to_stop(int cpuid)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop = jiffies + 10*HZ;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, stop)) {
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        if (!smp_secondary_alive)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("wait_boot_cpu_to_stop: FAILED on CPU %d, hanging now\n", cpuid);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Where secondaries begin a life of C.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1197d6a8a1c487422b772201927c454930377d8cf7eAl Virovoid __cpuinit
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_callin(void)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpuid = hard_smp_processor_id();
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell	if (cpu_online(cpuid)) {
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("??, cpu 0x%x already present??\n", cpuid);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1281371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell	set_cpu_online(cpuid, true);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on machine checks.  */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrmces(7);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set trap vectors.  */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	trap_init();
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set interrupt vector.  */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrent(entInt, 0);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get our local ticker going. */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(cpuid);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call platform-specific callin, if specified */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All kernel threads share the same mm context.  */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&init_mm.mm_count);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->active_mm = &init_mm;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
149e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	/* inform the notifiers about the new cpu */
150e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	notify_cpu_starting(cpuid);
151e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must have completely accurate bogos.  */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_enable();
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait boot CPU to stop with irq enabled before running
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   calibrate_delay. */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_boot_cpu_to_stop(cpuid);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	calibrate_delay();
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(cpuid);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allow master to continue only after we written loops_per_jiffy.  */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 1;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n",
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, current, current->active_mm));
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1696a6c0272f17cc80a8286d915f2ddf31557c2d559Frederic Weisbecker	preempt_disable();
170a123322d8afcfb5f86e0cc0062024084658aeeb2Thomas Gleixner	cpu_startup_entry(CPUHP_ONLINE);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
174f8d6c8d98d9ea7afef1e0d93d756a2dca879d1eaGreg Kroah-Hartmanstatic int
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_for_txrdy (unsigned long cpumask)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(hwrpb->txrdy & cpumask))
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(hwrpb->txrdy & cpumask))
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send a message to a secondary's console.  "START" is one such
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interesting message.  ;-)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1977d6a8a1c487422b772201927c454930377d8cf7eAl Virostatic void __cpuinit
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend_secondary_console_msg(char *str, int cpuid)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register char *cp1, *cp2;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cpumask;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t len;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpumask = (1UL << cpuid);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp2 = str;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = strlen(cp2);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(unsigned int *)&cpu->ipc_buffer[0] = len;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp1 = (char *) &cpu->ipc_buffer[1];
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp1, cp2, len);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* atomic test and set */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(cpuid, &hwrpb->rxrdy);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout:
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Processor %x not ready\n", cpuid);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A secondary console wants to send a message.  Receive it.
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrecv_secondary_console_msg(void)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mycpu, i, cnt;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long txrdy = hwrpb->txrdy;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *cp1, *cp2, buf[80];
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mycpu = hard_smp_processor_id();
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NR_CPUS; i++) {
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(txrdy & (1UL << i)))
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("recv_secondary_console_msg: "
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "TXRDY contains CPU %d.\n", i));
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpu = (struct percpu_struct *)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  ((char*)hwrpb
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + hwrpb->processor_offset
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + i * hwrpb->processor_size);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		DBGS(("recv_secondary_console_msg: on %d from %d"
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      mycpu, i, cpu->halt_reason, cpu->flags));
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cnt = cpu->ipc_buffer[0] >> 32;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cnt <= 0 || cnt >= 80)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(buf, "<<< BOGUS MSG >>>");
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp1 = (char *) &cpu->ipc_buffer[11];
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp2 = buf;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(cp2, cp1);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((cp2 = strchr(cp2, '\r')) != 0) {
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*cp2 = ' ';
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cp2[1] == '\n')
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					cp2[1] = ' ';
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS((KERN_INFO "recv_secondary_console_msg: on %d "
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "message is '%s'\n", mycpu, buf));
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->txrdy = 0;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convince the console to have a secondary cpu begin execution.
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2887d6a8a1c487422b772201927c454930377d8cf7eAl Virostatic int __cpuinit
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssecondary_cpu_start(int cpuid, struct task_struct *idle)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pcb_struct *hwpcb, *ipcb;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb = (struct pcb_struct *) cpu->hwpcb;
30037bfbaf995d2c1f8196ee04c9d6f68258d5ec3e8Al Viro	ipcb = &task_thread_info(idle)->pcb;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the CPU's HWPCB to something just good enough for
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   us to get started.  Immediately after starting, we'll swpctx
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to the target idle task's pcb.  Reuse the stack in the mean
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   time.  Precalculate the target PCBB.  */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ksp = (unsigned long)ipcb + sizeof(union thread_union) - 16;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->usp = 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ptbr = ipcb->ptbr;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->pcc = 0;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->asn = 0;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->unique = virt_to_phys(ipcb);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->flags = ipcb->flags;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->res1 = hwpcb->res2 = 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique));
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, ipcb->flags));
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart = __smp_callin;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Recalculate and update the HWRPB checksum */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb_update_checksum(hwrpb);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Send a "start" command to the specified processor.
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SRM III 3.4.1.3 */
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_secondary_console_msg("START\r\n", cpuid);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait 10 seconds for an ACK from the console.  */
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu->flags & 1)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto started;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds started:
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bring one cpu online.
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
359ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Virostatic int __cpuinit
3602ec9415c71a1ddad969602e690a9c848b81256b3Thomas Gleixnersmp_boot_one_cpu(int cpuid, struct task_struct *idle)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Signal the secondary to wait a moment.  */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = -1;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Whirrr, whirrr, whirrrrrrrrr... */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (secondary_cpu_start(cpuid, idle))
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Notify the secondary CPU it can run calibrate_delay.  */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 0;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We've been acked by the console; wait one second for
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the task to start up for real.  */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 1*HZ;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (smp_secondary_alive == 1)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto alive;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We failed to boot the CPU.  */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alive:
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Another "Red Snapper". */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called from setup_arch.  Detect an SMP system and which processors
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are present.
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_smp(void)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpubase, *cpu;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (boot_cpuid != 0) {
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       boot_cpuid);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->nr_processors > 1) {
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int boot_cpu_palrev;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("setup_smp: nr_processors %ld\n",
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      hwrpb->nr_processors));
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpubase = (struct percpu_struct *)
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((char*)hwrpb + hwrpb->processor_offset);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		boot_cpu_palrev = cpubase->pal_revision;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hwrpb->nr_processors; i++) {
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpu = (struct percpu_struct *)
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((char *)cpubase + i*hwrpb->processor_size);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((cpu->flags & 0x1cc) == 0x1cc) {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				smp_num_probed++;
4251371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell				set_cpu_possible(i, true);
4261371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell				set_cpu_present(i, true);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu->pal_revision = boot_cpu_palrev;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->flags, cpu->type));
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->pal_revision));
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_num_probed = 1;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4395f054e31c63be774bf1ce252f20d56012a00f8a5Rusty Russell	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
44081740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	       smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by smp_init prepare the secondaries
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_cpus(unsigned int max_cpus)
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Take care of some initial bookkeeping.  */
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ipi_data, 0, sizeof(ipi_data));
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->cpu = boot_cpuid;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(boot_cpuid);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(boot_cpuid);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Nothing to do on a UP box, or when told not to.  */
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_num_probed == 1 || max_cpus == 0) {
4591371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell		init_cpu_possible(cpumask_of(boot_cpuid));
4601371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell		init_cpu_present(cpumask_of(boot_cpuid));
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "SMP mode deactivated.\n");
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP starting up secondaries.\n");
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
467328c2a8a39e1ba43a6e54e43fc752f7035779561Ivan Kokshaysky	smp_num_cpus = smp_num_probed;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
470f8d6c8d98d9ea7afef1e0d93d756a2dca879d1eaGreg Kroah-Hartmanvoid
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_boot_cpu(void)
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
475ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Viroint __cpuinit
4768239c25f47d2b318156993b15f33900a86ea5e17Thomas Gleixner__cpu_up(unsigned int cpu, struct task_struct *tidle)
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4782ec9415c71a1ddad969602e690a9c848b81256b3Thomas Gleixner	smp_boot_one_cpu(cpu, tidle);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cpu_online(cpu) ? 0 : -ENOSYS;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_cpus_done(unsigned int max_cpus)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bogosum = 0;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(cpu = 0; cpu < NR_CPUS; cpu++)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu_online(cpu))
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bogosum += cpu_data[cpu].loops_per_jiffy;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP: Total of %d processors activated "
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       "(%lu.%02lu BogoMIPS).\n",
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       num_online_cpus(),
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (bogosum + 2500) / (500000/HZ),
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ((bogosum + 2500) / (5000/HZ)) % 100);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_percpu_timer_interrupt(struct pt_regs *regs)
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5048774cb815f2492a95b90a927f93a2de555753b32Al Viro	struct pt_regs *old_regs;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu = smp_processor_id();
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long user = user_mode(regs);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpuinfo_alpha *data = &cpu_data[cpu];
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5098774cb815f2492a95b90a927f93a2de555753b32Al Viro	old_regs = set_irq_regs(regs);
5108774cb815f2492a95b90a927f93a2de555753b32Al Viro
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Record kernel PC.  */
5128774cb815f2492a95b90a927f93a2de555753b32Al Viro	profile_tick(CPU_PROFILING);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!--data->prof_counter) {
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We need to make like a normal interrupt -- otherwise
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   timer interrupts ignore the global interrupt lock,
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   which would be a Bad Thing.  */
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_enter();
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		update_process_times(user);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->prof_counter = data->prof_multiplier;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_exit();
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5268774cb815f2492a95b90a927f93a2de555753b32Al Viro	set_irq_regs(old_regs);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
529ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Viroint
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_profiling_timer(unsigned int multiplier)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
53781065e4f2b525410d0c80040140e086abfbf7de2Rusty Russellsend_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
54281065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	for_each_cpu(i, to_whom)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(operation, &ipi_data[i].bits);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
54681065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	for_each_cpu(i, to_whom)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wripir(i);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_ipi(struct pt_regs *regs)
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_cpu = smp_processor_id();
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ops;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n",
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      this_cpu, *pending_ipis, regs->pc));
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();	/* Order interrupt and bit testing. */
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((ops = xchg(pending_ipis, 0)) != 0) {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order bit clearing and data access. */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  do {
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long which;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = ops & -ops;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ops &= ~which;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = __ffs(which);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (which) {
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_RESCHEDULE:
574184748cc50b2dceb8287f9fb657eda48ff8fcfe7Peter Zijlstra			scheduler_ipi();
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CALL_FUNC:
578c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_interrupt();
579c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			break;
580c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe
581c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe		case IPI_CALL_FUNC_SINGLE:
582c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_single_interrupt();
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CPU_STOP:
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			halt();
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       this_cpu, which);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  } while (ops);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order data access and bit testing. */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[this_cpu].ipi_count++;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->txrdy)
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		recv_secondary_console_msg();
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_reschedule(int cpu)
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu == hard_smp_processor_id())
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "smp_send_reschedule: Sending IPI to self.\n");
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
61281065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_stop(void)
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
61881740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_t to_whom;
61981740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_copy(&to_whom, cpu_possible_mask);
62081740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_clear_cpu(smp_processor_id(), &to_whom);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hard_smp_processor_id() != boot_cpu_id)
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
62581065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(&to_whom, IPI_CPU_STOP);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62881065e4f2b525410d0c80040140e086abfbf7de2Rusty Russellvoid arch_send_call_function_ipi_mask(const struct cpumask *mask)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
630c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe	send_ipi_message(mask, IPI_CALL_FUNC);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
633c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboevoid arch_send_call_function_single_ipi(int cpu)
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
63581065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_imb(void *ignored)
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imb();
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_imb(void)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must wait other processors to flush their icache before continue. */
64815c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_imb, NULL, 1))
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "smp_imb: timed out\n");
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
651cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_imb);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_all(void *ignored)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tbia();
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_all(void)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Although we don't have any data to pass, we do want to
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   synchronize with the other processors.  */
66415c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_flush_tlb_all, NULL, 1)) {
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_all: timed out\n");
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define asn_locked() (cpu_data[smp_processor_id()].asn_lock)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_mm(void *x)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_mm(struct mm_struct *mm)
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7018691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_mm, mm, 1)) {
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
707cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_mm);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct flush_tlb_page_struct {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vm_area_struct *vma;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_page(void *x)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct * mm = data->mm;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, data->vma, data->addr);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct data;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, vma, addr);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.vma = vma;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.mm = mm;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.addr = addr;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7548691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_page, &data, 1)) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_page: timed out\n");
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
760cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_page);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* On the Alpha we always flush the whole user tlb.  */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_tlb_mm(vma->vm_mm);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
768cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_range);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_icache_page(void *x)
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_icache_user_range(struct vm_area_struct *vma, struct page *page,
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long addr, int len)
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((vma->vm_flags & VM_EXEC) == 0)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8068691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_icache_page, mm, 1)) {
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_icache_page: timed out\n");
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
812