smp.c revision 7d6a8a1c487422b772201927c454930377d8cf7e
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>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/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.  */
71cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3Al Virostatic int smp_secondary_alive __devinitdata = 0;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Which cpus ids came online.  */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscpumask_t cpu_online_map;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cpu_online_map);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_probed;		/* Internal processor count */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_cpus = 1;		/* Number that came online.  */
80cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_num_cpus);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by both boot and secondaries to move global data into
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  per-processor storage.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_store_cpu_info(int cpuid)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].last_asn = ASN_FIRST_VERSION;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].need_new_asn = 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].asn_lock = 0;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_setup_percpu_timer(int cpuid)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_counter = 1;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_multiplier = 1;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_boot_cpu_to_stop(int cpuid)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop = jiffies + 10*HZ;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, stop)) {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        if (!smp_secondary_alive)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("wait_boot_cpu_to_stop: FAILED on CPU %d, hanging now\n", cpuid);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Where secondaries begin a life of C.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1247d6a8a1c487422b772201927c454930377d8cf7eAl Virovoid __cpuinit
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_callin(void)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpuid = hard_smp_processor_id();
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu_test_and_set(cpuid, cpu_online_map)) {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("??, cpu 0x%x already present??\n", cpuid);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on machine checks.  */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrmces(7);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set trap vectors.  */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	trap_init();
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set interrupt vector.  */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrent(entInt, 0);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get our local ticker going. */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(cpuid);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call platform-specific callin, if specified */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All kernel threads share the same mm context.  */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&init_mm.mm_count);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->active_mm = &init_mm;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	/* inform the notifiers about the new cpu */
154e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	notify_cpu_starting(cpuid);
155e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must have completely accurate bogos.  */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_enable();
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait boot CPU to stop with irq enabled before running
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   calibrate_delay. */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_boot_cpu_to_stop(cpuid);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	calibrate_delay();
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(cpuid);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allow master to continue only after we written loops_per_jiffy.  */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 1;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n",
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, current, current->active_mm));
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Do nothing.  */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_idle();
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
178cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3Al Virostatic int __devinit
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_for_txrdy (unsigned long cpumask)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(hwrpb->txrdy & cpumask))
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(hwrpb->txrdy & cpumask))
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send a message to a secondary's console.  "START" is one such
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interesting message.  ;-)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2017d6a8a1c487422b772201927c454930377d8cf7eAl Virostatic void __cpuinit
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend_secondary_console_msg(char *str, int cpuid)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register char *cp1, *cp2;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cpumask;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t len;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpumask = (1UL << cpuid);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp2 = str;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = strlen(cp2);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(unsigned int *)&cpu->ipc_buffer[0] = len;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp1 = (char *) &cpu->ipc_buffer[1];
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp1, cp2, len);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* atomic test and set */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(cpuid, &hwrpb->rxrdy);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout:
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Processor %x not ready\n", cpuid);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A secondary console wants to send a message.  Receive it.
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrecv_secondary_console_msg(void)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mycpu, i, cnt;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long txrdy = hwrpb->txrdy;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *cp1, *cp2, buf[80];
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mycpu = hard_smp_processor_id();
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NR_CPUS; i++) {
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(txrdy & (1UL << i)))
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("recv_secondary_console_msg: "
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "TXRDY contains CPU %d.\n", i));
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpu = (struct percpu_struct *)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  ((char*)hwrpb
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + hwrpb->processor_offset
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + i * hwrpb->processor_size);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		DBGS(("recv_secondary_console_msg: on %d from %d"
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      mycpu, i, cpu->halt_reason, cpu->flags));
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cnt = cpu->ipc_buffer[0] >> 32;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cnt <= 0 || cnt >= 80)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(buf, "<<< BOGUS MSG >>>");
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp1 = (char *) &cpu->ipc_buffer[11];
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp2 = buf;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(cp2, cp1);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((cp2 = strchr(cp2, '\r')) != 0) {
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*cp2 = ' ';
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cp2[1] == '\n')
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					cp2[1] = ' ';
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS((KERN_INFO "recv_secondary_console_msg: on %d "
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "message is '%s'\n", mycpu, buf));
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->txrdy = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convince the console to have a secondary cpu begin execution.
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2927d6a8a1c487422b772201927c454930377d8cf7eAl Virostatic int __cpuinit
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssecondary_cpu_start(int cpuid, struct task_struct *idle)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pcb_struct *hwpcb, *ipcb;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb = (struct pcb_struct *) cpu->hwpcb;
30437bfbaf995d2c1f8196ee04c9d6f68258d5ec3e8Al Viro	ipcb = &task_thread_info(idle)->pcb;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the CPU's HWPCB to something just good enough for
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   us to get started.  Immediately after starting, we'll swpctx
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to the target idle task's pcb.  Reuse the stack in the mean
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   time.  Precalculate the target PCBB.  */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ksp = (unsigned long)ipcb + sizeof(union thread_union) - 16;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->usp = 0;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ptbr = ipcb->ptbr;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->pcc = 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->asn = 0;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->unique = virt_to_phys(ipcb);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->flags = ipcb->flags;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->res1 = hwpcb->res2 = 0;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique));
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, ipcb->flags));
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart = __smp_callin;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Recalculate and update the HWRPB checksum */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb_update_checksum(hwrpb);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Send a "start" command to the specified processor.
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SRM III 3.4.1.3 */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_secondary_console_msg("START\r\n", cpuid);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait 10 seconds for an ACK from the console.  */
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu->flags & 1)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto started;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds started:
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bring one cpu online.
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
363ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Virostatic int __cpuinit
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_boot_one_cpu(int cpuid)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct task_struct *idle;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Cook up an idler for this guy.  Note that the address we
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   give to kernel_thread is irrelevant -- it's going to start
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   where HWRPB.CPU_restart says to start.  But this gets all
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the other task-y sort of data structures set up like we
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   wish.  We can't use kernel_thread since we must avoid
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   rescheduling the child.  */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	idle = fork_idle(cpuid);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(idle))
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("failed fork for CPU %d", cpuid);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, idle->flags));
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Signal the secondary to wait a moment.  */
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = -1;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Whirrr, whirrr, whirrrrrrrrr... */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (secondary_cpu_start(cpuid, idle))
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Notify the secondary CPU it can run calibrate_delay.  */
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 0;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We've been acked by the console; wait one second for
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the task to start up for real.  */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 1*HZ;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (smp_secondary_alive == 1)
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto alive;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We failed to boot the CPU.  */
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alive:
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Another "Red Snapper". */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called from setup_arch.  Detect an SMP system and which processors
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are present.
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_smp(void)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpubase, *cpu;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (boot_cpuid != 0) {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       boot_cpuid);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->nr_processors > 1) {
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int boot_cpu_palrev;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("setup_smp: nr_processors %ld\n",
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      hwrpb->nr_processors));
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpubase = (struct percpu_struct *)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((char*)hwrpb + hwrpb->processor_offset);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		boot_cpu_palrev = cpubase->pal_revision;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hwrpb->nr_processors; i++) {
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpu = (struct percpu_struct *)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((char *)cpubase + i*hwrpb->processor_size);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((cpu->flags & 0x1cc) == 0x1cc) {
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				smp_num_probed++;
443c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky				cpu_set(i, cpu_present_map);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu->pal_revision = boot_cpu_palrev;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->flags, cpu->type));
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->pal_revision));
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_num_probed = 1;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
456c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
457c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky	       smp_num_probed, cpu_present_map.bits[0]);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by smp_init prepare the secondaries
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_cpus(unsigned int max_cpus)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Take care of some initial bookkeeping.  */
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ipi_data, 0, sizeof(ipi_data));
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->cpu = boot_cpuid;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(boot_cpuid);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(boot_cpuid);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Nothing to do on a UP box, or when told not to.  */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_num_probed == 1 || max_cpus == 0) {
476c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky		cpu_present_map = cpumask_of_cpu(boot_cpuid);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "SMP mode deactivated.\n");
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP starting up secondaries.\n");
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
483328c2a8a39e1ba43a6e54e43fc752f7035779561Ivan Kokshaysky	smp_num_cpus = smp_num_probed;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __devinit
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_boot_cpu(void)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Viroint __cpuinit
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__cpu_up(unsigned int cpu)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_boot_one_cpu(cpu);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cpu_online(cpu) ? 0 : -ENOSYS;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_cpus_done(unsigned int max_cpus)
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bogosum = 0;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(cpu = 0; cpu < NR_CPUS; cpu++)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu_online(cpu))
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bogosum += cpu_data[cpu].loops_per_jiffy;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP: Total of %d processors activated "
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       "(%lu.%02lu BogoMIPS).\n",
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       num_online_cpus(),
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (bogosum + 2500) / (500000/HZ),
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ((bogosum + 2500) / (5000/HZ)) % 100);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_percpu_timer_interrupt(struct pt_regs *regs)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5208774cb815f2492a95b90a927f93a2de555753b32Al Viro	struct pt_regs *old_regs;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu = smp_processor_id();
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long user = user_mode(regs);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpuinfo_alpha *data = &cpu_data[cpu];
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5258774cb815f2492a95b90a927f93a2de555753b32Al Viro	old_regs = set_irq_regs(regs);
5268774cb815f2492a95b90a927f93a2de555753b32Al Viro
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Record kernel PC.  */
5288774cb815f2492a95b90a927f93a2de555753b32Al Viro	profile_tick(CPU_PROFILING);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!--data->prof_counter) {
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We need to make like a normal interrupt -- otherwise
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   timer interrupts ignore the global interrupt lock,
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   which would be a Bad Thing.  */
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_enter();
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		update_process_times(user);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->prof_counter = data->prof_multiplier;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_exit();
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5428774cb815f2492a95b90a927f93a2de555753b32Al Viro	set_irq_regs(old_regs);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
545ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Viroint
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_profiling_timer(unsigned int multiplier)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend_ipi_message(cpumask_t to_whom, enum ipi_message_type operation)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for_each_cpu_mask(i, to_whom)
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(operation, &ipi_data[i].bits);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for_each_cpu_mask(i, to_whom)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wripir(i);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_ipi(struct pt_regs *regs)
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_cpu = smp_processor_id();
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ops;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n",
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      this_cpu, *pending_ipis, regs->pc));
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();	/* Order interrupt and bit testing. */
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((ops = xchg(pending_ipis, 0)) != 0) {
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order bit clearing and data access. */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  do {
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long which;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = ops & -ops;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ops &= ~which;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = __ffs(which);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (which) {
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_RESCHEDULE:
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Reschedule callback.  Everything to be done
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   is done by the interrupt return path.  */
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CALL_FUNC:
595c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_interrupt();
596c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			break;
597c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe
598c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe		case IPI_CALL_FUNC_SINGLE:
599c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_single_interrupt();
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CPU_STOP:
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			halt();
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       this_cpu, which);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  } while (ops);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order data access and bit testing. */
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[this_cpu].ipi_count++;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->txrdy)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		recv_secondary_console_msg();
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_reschedule(int cpu)
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu == hard_smp_processor_id())
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "smp_send_reschedule: Sending IPI to self.\n");
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_stop(void)
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpumask_t to_whom = cpu_possible_map;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_clear(smp_processor_id(), to_whom);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hard_smp_processor_id() != boot_cpu_id)
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ipi_message(to_whom, IPI_CPU_STOP);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
644c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboevoid arch_send_call_function_ipi(cpumask_t mask)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
646c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe	send_ipi_message(mask, IPI_CALL_FUNC);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
649c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboevoid arch_send_call_function_single_ipi(int cpu)
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
651c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe	send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_imb(void *ignored)
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imb();
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_imb(void)
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must wait other processors to flush their icache before continue. */
66415c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_imb, NULL, 1))
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "smp_imb: timed out\n");
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
667cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_imb);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_all(void *ignored)
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tbia();
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_all(void)
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Although we don't have any data to pass, we do want to
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   synchronize with the other processors.  */
68015c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_flush_tlb_all, NULL, 1)) {
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_all: timed out\n");
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define asn_locked() (cpu_data[smp_processor_id()].asn_lock)
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_mm(void *x)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_mm(struct mm_struct *mm)
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7178691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_mm, mm, 1)) {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
723cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_mm);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct flush_tlb_page_struct {
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vm_area_struct *vma;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_page(void *x)
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct * mm = data->mm;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, data->vma, data->addr);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct data;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, vma, addr);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.vma = vma;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.mm = mm;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.addr = addr;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7708691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_page, &data, 1)) {
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_page: timed out\n");
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
776cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_page);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* On the Alpha we always flush the whole user tlb.  */
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_tlb_mm(vma->vm_mm);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
784cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_range);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_icache_page(void *x)
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_icache_user_range(struct vm_area_struct *vma, struct page *page,
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long addr, int len)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((vma->vm_flags & VM_EXEC) == 0)
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8228691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_icache_page, mm, 1)) {
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_icache_page: timed out\n");
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
828