smp.c revision cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3
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>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/threads.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/irq.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cache.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/profile.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hwrpb.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ptrace.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atomic.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgalloc.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mmu_context.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/tlbflush.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "proto.h"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "irq_impl.h"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_SMP 0
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_SMP
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBGS(args)	printk args
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBGS(args)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A collection of per-processor data.  */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpuinfo_alpha cpu_data[NR_CPUS];
54cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(cpu_data);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A collection of single bit ipi messages.  */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct {
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bits ____cacheline_aligned;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ipi_data[NR_CPUS] __cacheline_aligned;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum ipi_message_type {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_RESCHEDULE,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_CALL_FUNC,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IPI_CPU_STOP,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set to a secondary's cpuid when it comes online.  */
68cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3Al Virostatic int smp_secondary_alive __devinitdata = 0;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Which cpus ids came online.  */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscpumask_t cpu_online_map;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cpu_online_map);
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_probed;		/* Internal processor count */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint smp_num_cpus = 1;		/* Number that came online.  */
77cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_num_cpus);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern void calibrate_delay(void);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by both boot and secondaries to move global data into
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  per-processor storage.
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_store_cpu_info(int cpuid)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].last_asn = ASN_FIRST_VERSION;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].need_new_asn = 0;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].asn_lock = 0;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_setup_percpu_timer(int cpuid)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_counter = 1;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[cpuid].prof_multiplier = 1;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswait_boot_cpu_to_stop(int cpuid)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop = jiffies + 10*HZ;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, stop)) {
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        if (!smp_secondary_alive)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("wait_boot_cpu_to_stop: FAILED on CPU %d, hanging now\n", cpuid);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Where secondaries begin a life of C.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_callin(void)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpuid = hard_smp_processor_id();
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu_test_and_set(cpuid, cpu_online_map)) {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("??, cpu 0x%x already present??\n", cpuid);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on machine checks.  */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrmces(7);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set trap vectors.  */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	trap_init();
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set interrupt vector.  */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrent(entInt, 0);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get our local ticker going. */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(cpuid);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call platform-specific callin, if specified */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All kernel threads share the same mm context.  */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&init_mm.mm_count);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->active_mm = &init_mm;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
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
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Do nothing.  */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_idle();
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
176cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3Al Virostatic int __devinit
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 */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init
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 {
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp1 = (char *) &cpu->ipc_buffer[11];
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp2 = buf;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(cp2, cp1);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((cp2 = strchr(cp2, '\r')) != 0) {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*cp2 = ' ';
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cp2[1] == '\n')
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					cp2[1] = ' ';
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS((KERN_INFO "recv_secondary_console_msg: on %d "
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "message is '%s'\n", mycpu, buf));
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->txrdy = 0;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convince the console to have a secondary cpu begin execution.
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssecondary_cpu_start(int cpuid, struct task_struct *idle)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpu;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pcb_struct *hwpcb, *ipcb;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = (struct percpu_struct *)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((char*)hwrpb
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + hwrpb->processor_offset
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 + cpuid * hwrpb->processor_size);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb = (struct pcb_struct *) cpu->hwpcb;
30237bfbaf995d2c1f8196ee04c9d6f68258d5ec3e8Al Viro	ipcb = &task_thread_info(idle)->pcb;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the CPU's HWPCB to something just good enough for
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   us to get started.  Immediately after starting, we'll swpctx
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to the target idle task's pcb.  Reuse the stack in the mean
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   time.  Precalculate the target PCBB.  */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ksp = (unsigned long)ipcb + sizeof(union thread_union) - 16;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->usp = 0;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->ptbr = ipcb->ptbr;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->pcc = 0;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->asn = 0;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->unique = virt_to_phys(ipcb);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->flags = ipcb->flags;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwpcb->res1 = hwpcb->res2 = 0;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique));
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, ipcb->flags));
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart = __smp_callin;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Recalculate and update the HWRPB checksum */
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hwrpb_update_checksum(hwrpb);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Send a "start" command to the specified processor.
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SRM III 3.4.1.3 */
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_secondary_console_msg("START\r\n", cpuid);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait 10 seconds for an ACK from the console.  */
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 10*HZ;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu->flags & 1)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto started;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds started:
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bring one cpu online.
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361cc040a8a0e8ba95fbb0ae1edcb9ec83623b422e3Al Virostatic int __devinit
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_boot_one_cpu(int cpuid)
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct task_struct *idle;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Cook up an idler for this guy.  Note that the address we
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   give to kernel_thread is irrelevant -- it's going to start
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   where HWRPB.CPU_restart says to start.  But this gets all
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the other task-y sort of data structures set up like we
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   wish.  We can't use kernel_thread since we must avoid
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   rescheduling the child.  */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	idle = fork_idle(cpuid);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(idle))
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("failed fork for CPU %d", cpuid);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      cpuid, idle->state, idle->flags));
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Signal the secondary to wait a moment.  */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = -1;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Whirrr, whirrr, whirrrrrrrrr... */
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (secondary_cpu_start(cpuid, idle))
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Notify the secondary CPU it can run calibrate_delay.  */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_secondary_alive = 0;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We've been acked by the console; wait one second for
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the task to start up for real.  */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + 1*HZ;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (time_before(jiffies, timeout)) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (smp_secondary_alive == 1)
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto alive;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We failed to boot the CPU.  */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alive:
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Another "Red Snapper". */
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called from setup_arch.  Detect an SMP system and which processors
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are present.
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_smp(void)
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct percpu_struct *cpubase, *cpu;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long i;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (boot_cpuid != 0) {
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       boot_cpuid);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->nr_processors > 1) {
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int boot_cpu_palrev;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBGS(("setup_smp: nr_processors %ld\n",
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      hwrpb->nr_processors));
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpubase = (struct percpu_struct *)
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((char*)hwrpb + hwrpb->processor_offset);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		boot_cpu_palrev = cpubase->pal_revision;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hwrpb->nr_processors; i++) {
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpu = (struct percpu_struct *)
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((char *)cpubase + i*hwrpb->processor_size);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((cpu->flags & 0x1cc) == 0x1cc) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				smp_num_probed++;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Assume here that "whami" == index */
442c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky				cpu_set(i, cpu_present_map);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu->pal_revision = boot_cpu_palrev;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->flags, cpu->type));
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      i, cpu->pal_revision));
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_num_probed = 1;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
455c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
456c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky	       smp_num_probed, cpu_present_map.bits[0]);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by smp_init prepare the secondaries
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_cpus(unsigned int max_cpus)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Take care of some initial bookkeeping.  */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(ipi_data, 0, sizeof(ipi_data));
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->cpu = boot_cpuid;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_store_cpu_info(boot_cpuid);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_setup_percpu_timer(boot_cpuid);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Nothing to do on a UP box, or when told not to.  */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_num_probed == 1 || max_cpus == 0) {
475c7d2d28b9851d0ffc9924b0e36bac806d18ebf25Ivan Kokshaysky		cpu_present_map = cpumask_of_cpu(boot_cpuid);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "SMP mode deactivated.\n");
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP starting up secondaries.\n");
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
482328c2a8a39e1ba43a6e54e43fc752f7035779561Ivan Kokshaysky	smp_num_cpus = smp_num_probed;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __devinit
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_prepare_boot_cpu(void)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __devinit
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__cpu_up(unsigned int cpu)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_boot_one_cpu(cpu);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cpu_online(cpu) ? 0 : -ENOSYS;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_cpus_done(unsigned int max_cpus)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bogosum = 0;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(cpu = 0; cpu < NR_CPUS; cpu++)
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpu_online(cpu))
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bogosum += cpu_data[cpu].loops_per_jiffy;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "SMP: Total of %d processors activated "
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       "(%lu.%02lu BogoMIPS).\n",
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       num_online_cpus(),
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (bogosum + 2500) / (500000/HZ),
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       ((bogosum + 2500) / (5000/HZ)) % 100);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_percpu_timer_interrupt(struct pt_regs *regs)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5198774cb815f2492a95b90a927f93a2de555753b32Al Viro	struct pt_regs *old_regs;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpu = smp_processor_id();
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long user = user_mode(regs);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpuinfo_alpha *data = &cpu_data[cpu];
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5248774cb815f2492a95b90a927f93a2de555753b32Al Viro	old_regs = set_irq_regs(regs);
5258774cb815f2492a95b90a927f93a2de555753b32Al Viro
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Record kernel PC.  */
5278774cb815f2492a95b90a927f93a2de555753b32Al Viro	profile_tick(CPU_PROFILING);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!--data->prof_counter) {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We need to make like a normal interrupt -- otherwise
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   timer interrupts ignore the global interrupt lock,
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   which would be a Bad Thing.  */
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_enter();
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		update_process_times(user);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->prof_counter = data->prof_multiplier;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_exit();
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5418774cb815f2492a95b90a927f93a2de555753b32Al Viro	set_irq_regs(old_regs);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetup_profiling_timer(unsigned int multiplier)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend_ipi_message(cpumask_t to_whom, enum ipi_message_type operation)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for_each_cpu_mask(i, to_whom)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(operation, &ipi_data[i].bits);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for_each_cpu_mask(i, to_whom)
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wripir(i);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Structure and data for smp_call_function.  This is designed to
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   minimize static memory requirements.  Plus it looks cleaner.  */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct smp_call_struct {
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void (*func) (void *info);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *info;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long wait;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t unstarted_count;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t unfinished_count;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct smp_call_struct *smp_call_function_data;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Atomicly drop data into a shared pointer.  The pointer is free if
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it is initially locked.  If retry, spin until free.  */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspointer_lock (void *lock, void *data, int retry)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *old, *tmp;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds again:
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compare and swap with zero.  */
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asm volatile (
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"1:	ldq_l	%0,%1\n"
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"	mov	%3,%2\n"
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"	bne	%0,2f\n"
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"	stq_c	%2,%1\n"
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"	beq	%2,1b\n"
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"2:"
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "r"(data)
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "memory");
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old == 0)
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! retry)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (*(void **)lock)
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto again;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_ipi(struct pt_regs *regs)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_cpu = smp_processor_id();
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ops;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n",
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      this_cpu, *pending_ipis, regs->pc));
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();	/* Order interrupt and bit testing. */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((ops = xchg(pending_ipis, 0)) != 0) {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order bit clearing and data access. */
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  do {
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long which;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = ops & -ops;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ops &= ~which;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		which = __ffs(which);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (which) {
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_RESCHEDULE:
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Reschedule callback.  Everything to be done
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   is done by the interrupt return path.  */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CALL_FUNC:
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    {
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct smp_call_struct *data;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			void (*func)(void *info);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			void *info;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int wait;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data = smp_call_function_data;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func = data->func;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info = data->info;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			wait = data->wait;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Notify the sending CPU that the data has been
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   received, and execution is about to begin.  */
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mb();
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			atomic_dec (&data->unstarted_count);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* At this point the structure may be gone unless
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   wait is true.  */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(*func)(info);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Notify the sending CPU that the task is done.  */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mb();
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (wait) atomic_dec (&data->unfinished_count);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case IPI_CPU_STOP:
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			halt();
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       this_cpu, which);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  } while (ops);
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  mb();	/* Order data access and bit testing. */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_data[this_cpu].ipi_count++;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hwrpb->txrdy)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		recv_secondary_console_msg();
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_reschedule(int cpu)
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpu == hard_smp_processor_id())
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "smp_send_reschedule: Sending IPI to self.\n");
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_send_stop(void)
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpumask_t to_whom = cpu_possible_map;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_clear(smp_processor_id(), to_whom);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IPI_MSG
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (hard_smp_processor_id() != boot_cpu_id)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ipi_message(to_whom, IPI_CPU_STOP);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run a function on all other CPUs.
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  <func>	The function to run. This must be fast and non-blocking.
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  <info>	An arbitrary pointer to pass to the function.
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  <retry>	If true, keep retrying until ready.
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  <wait>	If true, wait until function has completed on other CPUs.
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  [RETURNS]   0 on success, else a negative status code.
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Does not return until remote CPUs are nearly ready to execute <func>
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or are or have executed.
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You must not call this function with disabled interrupts or from a
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware interrupt handler or from a bottom half handler.
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  int wait, cpumask_t to_whom)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct smp_call_struct data;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num_cpus_to_call;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Can deadlock when called with interrupts disabled */
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON(irqs_disabled());
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.func = func;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.info = info;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.wait = wait;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu_clear(smp_processor_id(), to_whom);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	num_cpus_to_call = cpus_weight(to_whom);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&data.unstarted_count, num_cpus_to_call);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&data.unfinished_count, num_cpus_to_call);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Acquire the smp_call_function_data mutex.  */
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pointer_lock(&smp_call_function_data, &data, retry))
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send a message to the requested CPUs.  */
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	send_ipi_message(to_whom, IPI_CALL_FUNC);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for a minimal response.  */
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies + HZ;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (atomic_read (&data.unstarted_count) > 0
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       && time_before (jiffies, timeout))
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		barrier();
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If there's no response yet, log a message but allow a longer
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * timeout period -- if we get a response this time, log
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * a message saying when we got it..
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&data.unstarted_count) > 0) {
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		long start_time = jiffies;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       __FUNCTION__);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timeout = jiffies + 30 * HZ;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (atomic_read(&data.unstarted_count) > 0
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       && time_before(jiffies, timeout))
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			barrier();
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&data.unstarted_count) <= 0) {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			long delta = jiffies - start_time;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s: response %ld.%ld seconds into long wait\n",
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       __FUNCTION__, delta / HZ,
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (100 * (delta - ((delta / HZ) * HZ))) / HZ);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We either got one or timed out -- clear the lock. */
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb();
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	smp_call_function_data = NULL;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If after both the initial and long timeout periods we still don't
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have a response, something is very wrong...
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(atomic_read (&data.unstarted_count) > 0);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for a complete response, if needed.  */
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (wait) {
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (atomic_read (&data.unfinished_count) > 0)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			barrier();
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
794cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_call_function_on_cpu);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_call_function (void (*func) (void *info), void *info, int retry, int wait)
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return smp_call_function_on_cpu (func, info, retry, wait,
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 cpu_online_map);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
802cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_call_function);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_imb(void *ignored)
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imb();
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssmp_imb(void)
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Must wait other processors to flush their icache before continue. */
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (on_each_cpu(ipi_imb, NULL, 1, 1))
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "smp_imb: timed out\n");
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
817cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(smp_imb);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_all(void *ignored)
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tbia();
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_all(void)
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Although we don't have any data to pass, we do want to
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   synchronize with the other processors.  */
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1)) {
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_all: timed out\n");
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define asn_locked() (cpu_data[smp_processor_id()].asn_lock)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_mm(void *x)
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_mm(struct mm_struct *mm)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current(mm);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
873cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_mm);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct flush_tlb_page_struct {
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vm_area_struct *vma;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_tlb_page(void *x)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct * mm = data->mm;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, data->vma, data->addr);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct flush_tlb_page_struct data;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_current_page(mm, vma, addr);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.vma = vma;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.mm = mm;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data.addr = addr;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_tlb_page: timed out\n");
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
926cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_page);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* On the Alpha we always flush the whole user tlb.  */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_tlb_mm(vma->vm_mm);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
934cff52daffa080eff6353f44df418b080dacefb96Al ViroEXPORT_SYMBOL(flush_tlb_range);
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsipi_flush_icache_page(void *x)
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = (struct mm_struct *) x;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm && !asn_locked())
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flush_tlb_other(mm);
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflush_icache_user_range(struct vm_area_struct *vma, struct page *page,
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long addr, int len)
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm = vma->vm_mm;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((vma->vm_flags & VM_EXEC) == 0)
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_disable();
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mm == current->active_mm) {
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__load_new_mm_context(mm);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&mm->mm_users) <= 1) {
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int cpu, this_cpu = smp_processor_id();
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cpu = 0; cpu < NR_CPUS; cpu++) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!cpu_online(cpu) || cpu == this_cpu)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (mm->context[cpu])
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mm->context[cpu] = 0;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			preempt_enable();
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (smp_call_function(ipi_flush_icache_page, mm, 1, 1)) {
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "flush_icache_page: timed out\n");
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	preempt_enable();
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
978