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 */
119ab39c77c3246f8462663fb1b07fa193f3e31e255Paul Gortmakervoid
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);
141a1659d6d128a7e0c2985bce7c957b66af1f71181Richard Henderson	init_clockevent();
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call platform-specific callin, if specified */
144a1659d6d128a7e0c2985bce7c957b66af1f71181Richard Henderson	if (alpha_mv.smp_callin)
145a1659d6d128a7e0c2985bce7c957b66af1f71181Richard Henderson		alpha_mv.smp_callin();
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All kernel threads share the same mm context.  */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&init_mm.mm_count);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->active_mm = &init_mm;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	/* inform the notifiers about the new cpu */
152e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul	notify_cpu_starting(cpuid);
153e545a6140b698b2494daf0b32107bdcc5e901390Manfred Spraul
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must have completely accurate bogos.  */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_enable();
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait boot CPU to stop with irq enabled before running
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   calibrate_delay. */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_boot_cpu_to_stop(cpuid);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	calibrate_delay();
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(cpuid);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allow master to continue only after we written loops_per_jiffy.  */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 1;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n",
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, current, current->active_mm));
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1716a6c0272f17cc80a8286d915f2ddf31557c2d559Frederic Weisbecker	preempt_disable();
172a123322d8afcfb5f86e0cc0062024084658aeeb2Thomas Gleixner	cpu_startup_entry(CPUHP_ONLINE);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
176f8d6c8d98d9ea7afef1e0d93d756a2dca879d1eaGreg Kroah-Hartmanstatic int
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_for_txrdy (unsigned long cpumask)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(hwrpb->txrdy & cpumask))
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(hwrpb->txrdy & cpumask))
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send a message to a secondary's console.  "START" is one such
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interesting message.  ;-)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
199ab39c77c3246f8462663fb1b07fa193f3e31e255Paul Gortmakerstatic void
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend_secondary_console_msg(char *str, int cpuid)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register char *cp1, *cp2;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cpumask;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t len;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpumask = (1UL << cpuid);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp2 = str;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = strlen(cp2);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(unsigned int *)&cpu->ipc_buffer[0] = len;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp1 = (char *) &cpu->ipc_buffer[1];
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp1, cp2, len);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* atomic test and set */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(cpuid, &hwrpb->rxrdy);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait_for_txrdy(cpumask))
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto timeout;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout:
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Processor %x not ready\n", cpuid);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A secondary console wants to send a message.  Receive it.
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrecv_secondary_console_msg(void)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mycpu, i, cnt;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long txrdy = hwrpb->txrdy;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *cp1, *cp2, buf[80];
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mycpu = hard_smp_processor_id();
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NR_CPUS; i++) {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(txrdy & (1UL << i)))
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("recv_secondary_console_msg: "
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "TXRDY contains CPU %d.\n", i));
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpu = (struct percpu_struct *)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  ((char*)hwrpb
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + hwrpb->processor_offset
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   + i * hwrpb->processor_size);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		DBGS(("recv_secondary_console_msg: on %d from %d"
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      mycpu, i, cpu->halt_reason, cpu->flags));
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cnt = cpu->ipc_buffer[0] >> 32;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cnt <= 0 || cnt >= 80)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(buf, "<<< BOGUS MSG >>>");
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
26991b678c8edb7d8abd444705df63b80af31ad13e8Chen Gang			cp1 = (char *) &cpu->ipc_buffer[1];
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp2 = buf;
27100ee03092a6e4b1d0ddc6b861ebb9ed8d13cc29bChen Gang			memcpy(cp2, cp1, cnt);
27200ee03092a6e4b1d0ddc6b861ebb9ed8d13cc29bChen Gang			cp2[cnt] = '\0';
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((cp2 = strchr(cp2, '\r')) != 0) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*cp2 = ' ';
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cp2[1] == '\n')
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					cp2[1] = ' ';
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS((KERN_INFO "recv_secondary_console_msg: on %d "
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "message is '%s'\n", mycpu, buf));
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->txrdy = 0;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convince the console to have a secondary cpu begin execution.
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291ab39c77c3246f8462663fb1b07fa193f3e31e255Paul Gortmakerstatic int
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssecondary_cpu_start(int cpuid, struct task_struct *idle)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pcb_struct *hwpcb, *ipcb;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb = (struct pcb_struct *) cpu->hwpcb;
30337bfbaf995d2c1f8196ee04c9d6f68258d5ec3e8Al Viro	ipcb = &task_thread_info(idle)->pcb;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the CPU's HWPCB to something just good enough for
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   us to get started.  Immediately after starting, we'll swpctx
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to the target idle task's pcb.  Reuse the stack in the mean
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   time.  Precalculate the target PCBB.  */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ksp = (unsigned long)ipcb + sizeof(union thread_union) - 16;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->usp = 0;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ptbr = ipcb->ptbr;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->pcc = 0;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->asn = 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->unique = virt_to_phys(ipcb);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->flags = ipcb->flags;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->res1 = hwpcb->res2 = 0;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique));
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, ipcb->flags));
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart = __smp_callin;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Recalculate and update the HWRPB checksum */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb_update_checksum(hwrpb);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Send a "start" command to the specified processor.
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SRM III 3.4.1.3 */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_secondary_console_msg("START\r\n", cpuid);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait 10 seconds for an ACK from the console.  */
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu->flags & 1)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto started;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds started:
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bring one cpu online.
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
362ab39c77c3246f8462663fb1b07fa193f3e31e255Paul Gortmakerstatic int
3632ec9415c71a1ddad969602e690a9c848b81256b3Thomas Gleixnersmp_boot_one_cpu(int cpuid, struct task_struct *idle)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Signal the secondary to wait a moment.  */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = -1;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Whirrr, whirrr, whirrrrrrrrr... */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (secondary_cpu_start(cpuid, idle))
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Notify the secondary CPU it can run calibrate_delay.  */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 0;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We've been acked by the console; wait one second for
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the task to start up for real.  */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 1*HZ;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (smp_secondary_alive == 1)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto alive;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We failed to boot the CPU.  */
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alive:
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Another "Red Snapper". */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called from setup_arch.  Detect an SMP system and which processors
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are present.
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_smp(void)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpubase, *cpu;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (boot_cpuid != 0) {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       boot_cpuid);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->nr_processors > 1) {
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int boot_cpu_palrev;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("setup_smp: nr_processors %ld\n",
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      hwrpb->nr_processors));
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpubase = (struct percpu_struct *)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((char*)hwrpb + hwrpb->processor_offset);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		boot_cpu_palrev = cpubase->pal_revision;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hwrpb->nr_processors; i++) {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpu = (struct percpu_struct *)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((char *)cpubase + i*hwrpb->processor_size);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((cpu->flags & 0x1cc) == 0x1cc) {
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				smp_num_probed++;
4281371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell				set_cpu_possible(i, true);
4291371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell				set_cpu_present(i, true);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu->pal_revision = boot_cpu_palrev;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->flags, cpu->type));
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->pal_revision));
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_num_probed = 1;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4425f054e31c63be774bf1ce252f20d56012a00f8a5Rusty Russell	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
44381740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	       smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by smp_init prepare the secondaries
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_cpus(unsigned int max_cpus)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Take care of some initial bookkeeping.  */
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ipi_data, 0, sizeof(ipi_data));
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->cpu = boot_cpuid;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(boot_cpuid);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(boot_cpuid);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Nothing to do on a UP box, or when told not to.  */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_num_probed == 1 || max_cpus == 0) {
4621371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell		init_cpu_possible(cpumask_of(boot_cpuid));
4631371be0f7c8f6141b2dbfde6a7ae7885bedb9834Rusty Russell		init_cpu_present(cpumask_of(boot_cpuid));
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "SMP mode deactivated.\n");
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP starting up secondaries.\n");
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
470328c2a8a39e1ba43a6e54e43fc752f7035779561Ivan Kokshaysky	smp_num_cpus = smp_num_probed;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
473f8d6c8d98d9ea7afef1e0d93d756a2dca879d1eaGreg Kroah-Hartmanvoid
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_boot_cpu(void)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
478ab39c77c3246f8462663fb1b07fa193f3e31e255Paul Gortmakerint
4798239c25f47d2b318156993b15f33900a86ea5e17Thomas Gleixner__cpu_up(unsigned int cpu, struct task_struct *tidle)
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4812ec9415c71a1ddad969602e690a9c848b81256b3Thomas Gleixner	smp_boot_one_cpu(cpu, tidle);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cpu_online(cpu) ? 0 : -ENOSYS;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_cpus_done(unsigned int max_cpus)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bogosum = 0;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(cpu = 0; cpu < NR_CPUS; cpu++)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu_online(cpu))
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bogosum += cpu_data[cpu].loops_per_jiffy;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP: Total of %d processors activated "
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       "(%lu.%02lu BogoMIPS).\n",
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       num_online_cpus(),
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (bogosum + 2500) / (500000/HZ),
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ((bogosum + 2500) / (5000/HZ)) % 100);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
503ed5f6561436a1a0b38f4130bdb1fed00f14e60b5Al Viroint
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_profiling_timer(unsigned int multiplier)
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
51181065e4f2b525410d0c80040140e086abfbf7de2Rusty Russellsend_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
51681065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	for_each_cpu(i, to_whom)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(operation, &ipi_data[i].bits);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
52081065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	for_each_cpu(i, to_whom)
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wripir(i);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_ipi(struct pt_regs *regs)
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_cpu = smp_processor_id();
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ops;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n",
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      this_cpu, *pending_ipis, regs->pc));
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();	/* Order interrupt and bit testing. */
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((ops = xchg(pending_ipis, 0)) != 0) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order bit clearing and data access. */
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  do {
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long which;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = ops & -ops;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ops &= ~which;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = __ffs(which);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (which) {
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_RESCHEDULE:
548184748cc50b2dceb8287f9fb657eda48ff8fcfe7Peter Zijlstra			scheduler_ipi();
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CALL_FUNC:
552c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_interrupt();
553c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			break;
554c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe
555c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe		case IPI_CALL_FUNC_SINGLE:
556c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe			generic_smp_call_function_single_interrupt();
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CPU_STOP:
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			halt();
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       this_cpu, which);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  } while (ops);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order data access and bit testing. */
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[this_cpu].ipi_count++;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->txrdy)
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		recv_secondary_console_msg();
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_reschedule(int cpu)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu == hard_smp_processor_id())
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "smp_send_reschedule: Sending IPI to self.\n");
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
58681065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_stop(void)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
59281740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_t to_whom;
59381740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_copy(&to_whom, cpu_possible_mask);
59481740fc6b2144f5d197affb10f3c4062fddf21e4KOSAKI Motohiro	cpumask_clear_cpu(smp_processor_id(), &to_whom);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hard_smp_processor_id() != boot_cpu_id)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
59981065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(&to_whom, IPI_CPU_STOP);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60281065e4f2b525410d0c80040140e086abfbf7de2Rusty Russellvoid arch_send_call_function_ipi_mask(const struct cpumask *mask)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
604c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboe	send_ipi_message(mask, IPI_CALL_FUNC);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
607c524a1d8914408fd57241d9542fa2d402f004a33Jens Axboevoid arch_send_call_function_single_ipi(int cpu)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
60981065e4f2b525410d0c80040140e086abfbf7de2Rusty Russell	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_imb(void *ignored)
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imb();
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_imb(void)
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must wait other processors to flush their icache before continue. */
62215c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_imb, NULL, 1))
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "smp_imb: timed out\n");
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
625cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_imb);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_all(void *ignored)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tbia();
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_all(void)
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Although we don't have any data to pass, we do want to
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   synchronize with the other processors.  */
63815c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0dJens Axboe	if (on_each_cpu(ipi_flush_tlb_all, NULL, 1)) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_all: timed out\n");
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define asn_locked() (cpu_data[smp_processor_id()].asn_lock)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_mm(void *x)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_mm(struct mm_struct *mm)
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6758691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_mm, mm, 1)) {
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_mm);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct flush_tlb_page_struct {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vm_area_struct *vma;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_page(void *x)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct * mm = data->mm;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, data->vma, data->addr);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct data;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, vma, addr);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.vma = vma;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.mm = mm;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.addr = addr;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7288691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_tlb_page, &data, 1)) {
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_page: timed out\n");
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
734cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_page);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* On the Alpha we always flush the whole user tlb.  */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_tlb_mm(vma->vm_mm);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
742cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_range);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_icache_page(void *x)
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_icache_user_range(struct vm_area_struct *vma, struct page *page,
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long addr, int len)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((vma->vm_flags & VM_EXEC) == 0)
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7808691e5a8f691cc2a4fda0651e8d307aaba0e7d68Jens Axboe	if (smp_call_function(ipi_flush_icache_page, mm, 1)) {
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_icache_page: timed out\n");
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
786