patch-2.4.5 linux/arch/ppc/kernel/smp.c

Next file: linux/arch/ppc/kernel/softemu8xx.c
Previous file: linux/arch/ppc/kernel/sleep.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
@@ -1,4 +1,7 @@
 /*
+ * BK Id: SCCS/s.smp.c 1.23 05/17/01 18:14:22 cort
+ */
+/*
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
@@ -40,6 +43,7 @@
 #include <asm/residual.h>
 #include <asm/feature.h>
 #include <asm/time.h>
+#include <asm/gemini.h>
 
 #include "open_pic.h"
 int smp_threads_ready;
@@ -55,7 +59,7 @@
 unsigned int prof_counter[NR_CPUS];
 cycles_t cacheflush_time;
 static int max_cpus __initdata = NR_CPUS;
-
+unsigned long cpu_online_map;
 int smp_hw_index[NR_CPUS];
 
 /* all cpu mappings are 1-1 -- Cort */
@@ -452,32 +456,48 @@
 static void
 smp_core99_kick_cpu(int nr)
 {
-	unsigned long save_int;
+	unsigned long save_vector, new_vector;
 	unsigned long flags;
+#if 1 /* New way... */
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x100));
+	if (nr < 1 || nr > 3)
+		return;
+#else
 	volatile unsigned long *vector
 		 = ((volatile unsigned long *)(KERNELBASE+0x500));
-
 	if (nr != 1)
 		return;
+#endif
 	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
 	local_irq_save(flags);
 	local_irq_disable();
 	
-	/* Save EE vector */
-	save_int = *vector;
+	/* Save reset vector */
+	save_vector = *vector;
 	
-	/* Setup fake EE vector that does	  
+	/* Setup fake reset vector that does	  
 	 *   b __secondary_start_psurge - KERNELBASE
-	 */   
-	*vector = 0x48000002 +
-		((unsigned long)__secondary_start_psurge - KERNELBASE);
+	 */  
+	switch(nr) {
+		case 1:
+			new_vector = (unsigned long)__secondary_start_psurge;
+			break;
+		case 2:
+			new_vector = (unsigned long)__secondary_start_psurge2;
+			break;
+		case 3:
+			new_vector = (unsigned long)__secondary_start_psurge3;
+			break;
+	}
+	*vector = 0x48000002 + new_vector - KERNELBASE;
 	
 	/* flush data cache and inval instruction cache */
 	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
 	
 	/* Put some life in our friend */
-	feature_core99_kick_cpu1();
+	feature_core99_kick_cpu(nr);
 	
 	/* FIXME: We wait a bit for the CPU to take the exception, I should
 	 * instead wait for the entry code to set something for me. Well,
@@ -487,11 +507,11 @@
 	mdelay(1);
 	
 	/* Restore our exception vector */
-	*vector = save_int;
+	*vector = save_vector;
 	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
 	
 	local_irq_restore(flags);
-	if (ppc_md.progress) ppc_md.progress("smp_core99_probe done", 0x347);
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
 }
 
 static void
@@ -628,6 +648,43 @@
 		do_openpic_setup_cpu();
 }
 
+#ifdef CONFIG_GEMINI	
+static int
+smp_gemini_probe(void)
+{
+	int i, nr;
+
+        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
+	if (nr == 0)
+		nr = 4;
+
+	if (nr > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < nr; ++i)
+			smp_hw_index[i] = i;
+	}
+
+	return nr;
+}
+
+static void
+smp_gemini_kick_cpu(int nr)
+{
+	openpic_init_processor( 1<<i );
+	openpic_init_processor( 0 );
+}
+
+static void
+smp_gemini_setup_cpu(void)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+	if (cpu_nr > 0)
+		gemini_init_l2();
+}
+#endif /* CONFIG_GEMINI */
+
+
 static struct smp_ops_t {
 	void  (*message_pass)(int target, int msg, unsigned long data, int wait);
 	int   (*probe)(void);
@@ -685,6 +742,16 @@
 	smp_prep_setup_cpu,
 };
 
+#ifdef CONFIG_GEMINI	
+/* Gemini */
+static struct smp_ops_t gemini_smp_ops = {
+	smp_openpic_message_pass,
+	smp_gemini_probe,
+	smp_gemini_kick_cpu,
+	smp_gemini_setup_cpu,
+};
+#endif /* CONFIG_GEMINI	*/
+
 /* 
  * Common functions
  */
@@ -925,6 +992,11 @@
 	case _MACH_prep:
 		smp_ops = &prep_smp_ops;
 		break;
+#ifdef CONFIG_GEMINI		
+	case _MACH_gemini:
+		smp_ops = &gemini_smp_ops;
+		break;
+#endif /* CONFIG_GEMINI	*/
 	default:
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -946,6 +1018,19 @@
 		/* create a process for the processor */
 		/* we don't care about the values in regs since we'll
 		   never reschedule the forked task. */
+		/* We DO care about one bit in the pt_regs we
+		   pass to do_fork.  That is the MSR_FP bit in 
+		   regs.msr.  If that bit is on, then do_fork
+		   (via copy_thread) will call giveup_fpu.
+		   giveup_fpu will get a pointer to our (current's)
+		   last register savearea via current->thread.regs 
+		   and using that pointer will turn off the MSR_FP,
+		   MSR_FE0 and MSR_FE1 bits.  At this point, this 
+		   pointer is pointing to some arbitrary point within
+		   our stack. */
+
+		memset(&regs, 0, sizeof(struct pt_regs));
+		
 		if (do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0) < 0)
 			panic("failed fork for CPU %d", i);
 		p = init_task.prev_task;
@@ -1114,8 +1199,18 @@
 
 	init_idle();
 
+	/*
+	 * This cpu is now "online".  Only set them online
+	 * before they enter the loop below since write access
+	 * to the below variable is _not_ guaranteed to be
+	 * atomic.
+	 *   -- Cort <cort@fsmlabs.com>
+	 */
+	cpu_online_map |= 1UL << smp_processor_id();
+	
 	while(!smp_commenced)
 		barrier();
+
 	/* see smp_commence for more info */
 	if (!smp_tb_synchronized && smp_num_cpus == 2) {
 		smp_software_tb_sync(cpu);

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