/* * linux/arch/alpha/kernel/smp.c * * 2001-07-09 Phil Ezolt (Phillip.Ezolt@compaq.com) * Renamed modified smp_call_function to smp_call_function_on_cpu() * Created an function that conforms to the old calling convention * of smp_call_function(). * * This is helpful for DCPI. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "proto.h" #include "irq_impl.h" #define DEBUG_SMP 0 #if DEBUG_SMP #define DBGS(args) printk args #else #define DBGS(args) #endif /* A collection of per-processor data. */ struct cpuinfo_alpha cpu_data[NR_CPUS]; EXPORT_SYMBOL(cpu_data); /* A collection of single bit ipi messages. */ static struct { unsigned long bits ____cacheline_aligned; } ipi_data[NR_CPUS] __cacheline_aligned; enum ipi_message_type { IPI_RESCHEDULE, IPI_CALL_FUNC, IPI_CALL_FUNC_SINGLE, IPI_CPU_STOP, }; /* Set to a secondary's cpuid when it comes online. */ static int smp_secondary_alive = 0; int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ EXPORT_SYMBOL(smp_num_cpus); /* * Called by both boot and secondaries to move global data into * per-processor storage. */ static inline void __init smp_store_cpu_info(int cpuid) { cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy; cpu_data[cpuid].last_asn = ASN_FIRST_VERSION; cpu_data[cpuid].need_new_asn = 0; cpu_data[cpuid].asn_lock = 0; } /* * Ideally sets up per-cpu profiling hooks. Doesn't do much now... */ static inline void __init smp_setup_percpu_timer(int cpuid) { cpu_data[cpuid].prof_counter = 1; cpu_data[cpuid].prof_multiplier = 1; } static void __init wait_boot_cpu_to_stop(int cpuid) { unsigned long stop = jiffies + 10*HZ; while (time_before(jiffies, stop)) { if (!smp_secondary_alive) return; barrier(); } printk("wait_boot_cpu_to_stop: FAILED on CPU %d, hanging now\n", cpuid); for (;;) barrier(); } /* * Where secondaries begin a life of C. */ void __cpuinit smp_callin(void) { int cpuid = hard_smp_processor_id(); if (cpu_online(cpuid)) { printk("??, cpu 0x%x already present??\n", cpuid); BUG(); } set_cpu_online(cpuid, true); /* Turn on machine checks. */ wrmces(7); /* Set trap vectors. */ trap_init(); /* Set interrupt vector. */ wrent(entInt, 0); /* Get our local ticker going. */ smp_setup_percpu_timer(cpuid); /* Call platform-specific callin, if specified */ if (alpha_mv.smp_callin) alpha_mv.smp_callin(); /* All kernel threads share the same mm context. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; /* inform the notifiers about the new cpu */ notify_cpu_starting(cpuid); /* Must have completely accurate bogos. */ local_irq_enable(); /* Wait boot CPU to stop with irq enabled before running calibrate_delay. */ wait_boot_cpu_to_stop(cpuid); mb(); calibrate_delay(); smp_store_cpu_info(cpuid); /* Allow master to continue only after we written loops_per_jiffy. */ wmb(); smp_secondary_alive = 1; DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n", cpuid, current, current->active_mm));