patch-2.4.20 linux-2.4.20/arch/mips/sibyte/sb1250/smp.c

Next file: linux-2.4.20/arch/mips/sibyte/sb1250/time.c
Previous file: linux-2.4.20/arch/mips/sibyte/sb1250/setup.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/arch/mips/sibyte/sb1250/smp.c linux-2.4.20/arch/mips/sibyte/sb1250/smp.c
@@ -10,18 +10,24 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/mmu_context.h>
 #include <asm/sibyte/64bit.h>
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_regs.h>
-#include <asm/addrspace.h>
-#include <asm/smp.h>
-#include <linux/sched.h>
+#include <asm/sibyte/sb1250_int.h>
+
+extern void smp_call_function_interrupt(void);
 
 /*
  * These are routines for dealing with the sb1250 smp capabilities
@@ -29,17 +35,17 @@
  */
 
 static u64 mailbox_set_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU
 };
 
 static u64 mailbox_clear_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU
 };
 
 static u64 mailbox_regs[] = {
-	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU, 
+	KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU,
 	KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU
 };
 
@@ -66,7 +72,8 @@
 {
 	int cpu = smp_processor_id();
 	unsigned int action;
-	
+
+	kstat.irqs[cpu][K_INT_MBOX_0]++;
 	/* Load the mailbox register to figure out what we're supposed to do */
 	action = (in64(mailbox_regs[cpu]) >> 48) & 0xffff;
 
@@ -82,3 +89,68 @@
 		smp_call_function_interrupt();
 	}
 }
+
+extern atomic_t cpus_booted;
+extern int prom_setup_smp(void);
+extern int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp);
+
+void __init smp_boot_cpus(void)
+{
+	int i;
+	int cur_cpu = 0;
+
+	smp_num_cpus = prom_setup_smp();
+	init_new_context(current, &init_mm);
+	current->processor = 0;
+	cpu_data[0].udelay_val = loops_per_jiffy;
+	cpu_data[0].asid_cache = ASID_FIRST_VERSION;
+	CPUMASK_CLRALL(cpu_online_map);
+	CPUMASK_SETB(cpu_online_map, 0);
+	atomic_set(&cpus_booted, 1);  /* Master CPU is already booted... */
+	init_idle();
+
+	/*
+	 * This loop attempts to compensate for "holes" in the CPU
+	 * numbering.  It's overkill, but general.
+	 */
+	for (i = 1; i < smp_num_cpus; ) {
+		struct task_struct *p;
+		struct pt_regs regs;
+		int retval;
+		printk("Starting CPU %d... ", i);
+
+		/* Spawn a new process normally.  Grab a pointer to
+		   its task struct so we can mess with it */
+		do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+		p = init_task.prev_task;
+
+		/* Schedule the first task manually */
+		p->processor = i;
+		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+
+		/* Attach to the address space of init_task. */
+		atomic_inc(&init_mm.mm_count);
+		p->active_mm = &init_mm;
+		init_tasks[i] = p;
+
+		del_from_runqueue(p);
+		unhash_process(p);
+
+		do {
+			/* Iterate until we find a CPU that comes up */
+			cur_cpu++;
+			retval = prom_boot_secondary(cur_cpu,
+					    (unsigned long)p + KERNEL_STACK_SIZE - 32,
+					    (unsigned long)p);
+		} while (!retval && (cur_cpu < NR_CPUS));
+		if (retval) {
+			i++;
+		} else {
+			panic("CPU discovery disaster");
+		}
+	}
+
+	/* Wait for everyone to come up */
+	while (atomic_read(&cpus_booted) != smp_num_cpus);
+	smp_threads_ready = 1;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)