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