|
@@ -33,3 +33,135 @@
|
|
|
#include <asm/ptrace.h>
|
|
|
#include <linux/atomic.h>
|
|
|
|
|
|
+#include <asm/io.h>
|
|
|
+#include <asm/irq.h>
|
|
|
+#include <asm/pgtable.h>
|
|
|
+#include <asm/pgalloc.h>
|
|
|
+#include <asm/mmu_context.h>
|
|
|
+#include <asm/tlbflush.h>
|
|
|
+
|
|
|
+#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));
|