|
@@ -307,3 +307,196 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
|
|
|
hwpcb->ksp = (unsigned long)ipcb + sizeof(union thread_union) - 16;
|
|
|
hwpcb->usp = 0;
|
|
|
hwpcb->ptbr = ipcb->ptbr;
|
|
|
+ hwpcb->pcc = 0;
|
|
|
+ hwpcb->asn = 0;
|
|
|
+ hwpcb->unique = virt_to_phys(ipcb);
|
|
|
+ hwpcb->flags = ipcb->flags;
|
|
|
+ hwpcb->res1 = hwpcb->res2 = 0;
|
|
|
+
|
|
|
+#if 0
|
|
|
+ DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
|
|
|
+ hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique));
|
|
|
+#endif
|
|
|
+ DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
|
|
|
+ cpuid, idle->state, ipcb->flags));
|
|
|
+
|
|
|
+ /* Setup HWRPB fields that SRM uses to activate secondary CPU */
|
|
|
+ hwrpb->CPU_restart = __smp_callin;
|
|
|
+ hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
|
|
|
+
|
|
|
+ /* Recalculate and update the HWRPB checksum */
|
|
|
+ hwrpb_update_checksum(hwrpb);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Send a "start" command to the specified processor.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* SRM III 3.4.1.3 */
|
|
|
+ cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */
|
|
|
+ cpu->flags &= ~1; /* turn off Bootstrap In Progress */
|
|
|
+ wmb();
|
|
|
+
|
|
|
+ send_secondary_console_msg("START\r\n", cpuid);
|
|
|
+
|
|
|
+ /* Wait 10 seconds for an ACK from the console. */
|
|
|
+ timeout = jiffies + 10*HZ;
|
|
|
+ while (time_before(jiffies, timeout)) {
|
|
|
+ if (cpu->flags & 1)
|
|
|
+ goto started;
|
|
|
+ udelay(10);
|
|
|
+ barrier();
|
|
|
+ }
|
|
|
+ printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ started:
|
|
|
+ DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Bring one cpu online.
|
|
|
+ */
|
|
|
+static int __cpuinit
|
|
|
+smp_boot_one_cpu(int cpuid, struct task_struct *idle)
|
|
|
+{
|
|
|
+ unsigned long timeout;
|
|
|
+
|
|
|
+ /* Signal the secondary to wait a moment. */
|
|
|
+ smp_secondary_alive = -1;
|
|
|
+
|
|
|
+ /* Whirrr, whirrr, whirrrrrrrrr... */
|
|
|
+ if (secondary_cpu_start(cpuid, idle))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ /* Notify the secondary CPU it can run calibrate_delay. */
|
|
|
+ mb();
|
|
|
+ smp_secondary_alive = 0;
|
|
|
+
|
|
|
+ /* We've been acked by the console; wait one second for
|
|
|
+ the task to start up for real. */
|
|
|
+ timeout = jiffies + 1*HZ;
|
|
|
+ while (time_before(jiffies, timeout)) {
|
|
|
+ if (smp_secondary_alive == 1)
|
|
|
+ goto alive;
|
|
|
+ udelay(10);
|
|
|
+ barrier();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We failed to boot the CPU. */
|
|
|
+
|
|
|
+ printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ alive:
|
|
|
+ /* Another "Red Snapper". */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Called from setup_arch. Detect an SMP system and which processors
|
|
|
+ * are present.
|
|
|
+ */
|
|
|
+void __init
|
|
|
+setup_smp(void)
|
|
|
+{
|
|
|
+ struct percpu_struct *cpubase, *cpu;
|
|
|
+ unsigned long i;
|
|
|
+
|
|
|
+ if (boot_cpuid != 0) {
|
|
|
+ printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
|
|
|
+ boot_cpuid);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hwrpb->nr_processors > 1) {
|
|
|
+ int boot_cpu_palrev;
|
|
|
+
|
|
|
+ DBGS(("setup_smp: nr_processors %ld\n",
|
|
|
+ hwrpb->nr_processors));
|
|
|
+
|
|
|
+ cpubase = (struct percpu_struct *)
|
|
|
+ ((char*)hwrpb + hwrpb->processor_offset);
|
|
|
+ boot_cpu_palrev = cpubase->pal_revision;
|
|
|
+
|
|
|
+ for (i = 0; i < hwrpb->nr_processors; i++) {
|
|
|
+ cpu = (struct percpu_struct *)
|
|
|
+ ((char *)cpubase + i*hwrpb->processor_size);
|
|
|
+ if ((cpu->flags & 0x1cc) == 0x1cc) {
|
|
|
+ smp_num_probed++;
|
|
|
+ set_cpu_possible(i, true);
|
|
|
+ set_cpu_present(i, true);
|
|
|
+ cpu->pal_revision = boot_cpu_palrev;
|
|
|
+ }
|
|
|
+
|
|
|
+ DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
|
|
|
+ i, cpu->flags, cpu->type));
|
|
|
+ DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
|
|
|
+ i, cpu->pal_revision));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ smp_num_probed = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
|
|
|
+ smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Called by smp_init prepare the secondaries
|
|
|
+ */
|
|
|
+void __init
|
|
|
+smp_prepare_cpus(unsigned int max_cpus)
|
|
|
+{
|
|
|
+ /* Take care of some initial bookkeeping. */
|
|
|
+ memset(ipi_data, 0, sizeof(ipi_data));
|
|
|
+
|
|
|
+ current_thread_info()->cpu = boot_cpuid;
|
|
|
+
|
|
|
+ smp_store_cpu_info(boot_cpuid);
|
|
|
+ smp_setup_percpu_timer(boot_cpuid);
|
|
|
+
|
|
|
+ /* Nothing to do on a UP box, or when told not to. */
|
|
|
+ if (smp_num_probed == 1 || max_cpus == 0) {
|
|
|
+ init_cpu_possible(cpumask_of(boot_cpuid));
|
|
|
+ init_cpu_present(cpumask_of(boot_cpuid));
|
|
|
+ printk(KERN_INFO "SMP mode deactivated.\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "SMP starting up secondaries.\n");
|
|
|
+
|
|
|
+ smp_num_cpus = smp_num_probed;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+smp_prepare_boot_cpu(void)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+int __cpuinit
|
|
|
+__cpu_up(unsigned int cpu, struct task_struct *tidle)
|
|
|
+{
|
|
|
+ smp_boot_one_cpu(cpu, tidle);
|
|
|
+
|
|
|
+ return cpu_online(cpu) ? 0 : -ENOSYS;
|
|
|
+}
|
|
|
+
|
|
|
+void __init
|
|
|
+smp_cpus_done(unsigned int max_cpus)
|
|
|
+{
|
|
|
+ int cpu;
|
|
|
+ unsigned long bogosum = 0;
|
|
|
+
|
|
|
+ for(cpu = 0; cpu < NR_CPUS; cpu++)
|
|
|
+ if (cpu_online(cpu))
|
|
|
+ bogosum += cpu_data[cpu].loops_per_jiffy;
|
|
|
+
|
|
|
+ printk(KERN_INFO "SMP: Total of %d processors activated "
|
|
|
+ "(%lu.%02lu BogoMIPS).\n",
|
|
|
+ num_online_cpus(),
|
|
|
+ (bogosum + 2500) / (500000/HZ),
|
|
|
+ ((bogosum + 2500) / (5000/HZ)) % 100);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void
|