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

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

diff -u --recursive --new-file v2.2.3/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: smp.c,v 1.48 1999/03/16 10:40:32 cort Exp $
  *
  * Smp support for ppc.
  *
@@ -18,6 +18,7 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 #include <linux/init.h>
+#include <linux/openpic.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -29,9 +30,10 @@
 #include <asm/softirq.h>
 #include <asm/init.h>
 #include <asm/io.h>
+#include <asm/prom.h>
 
 #include "time.h"
-
+int first_cpu_booted = 0;
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
 int smp_num_cpus = 1;
@@ -42,7 +44,6 @@
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
-int first_cpu_booted = 0;
 cycles_t cacheflush_time;
 
 /* all cpu mappings are 1-1 -- Cort */
@@ -51,6 +52,10 @@
 
 int start_secondary(void *);
 extern int cpu_idle(void *unused);
+u_int openpic_read(volatile u_int *addr);
+
+/* register for interrupting the secondary processor on the powersurge */
+#define PSURGE_INTR	((volatile unsigned *)0xf80000c0)
 
 void smp_local_timer_interrupt(struct pt_regs * regs)
 {
@@ -99,29 +104,33 @@
 
 /*
  * Dirty hack to get smp message passing working.
- * Right now it only works for stop cpu's but will be setup
- * later for more general message passing.
  *
  * As it is now, if we're sending two message at the same time
- * we have race conditions.  I avoided doing locks here since
- * all that works right now is the stop cpu message.
+ * we have race conditions.  The PowerSurge doesn't easily
+ * allow us to send IPI messages so we put the messages in
+ * smp_message[].
  *
+ * This is because don't have several IPI's on the PowerSurge even though
+ * we do on the chrp.  It would be nice to use the actual IPI's on the chrp
+ * rather than this but having two methods of doing IPI isn't a good idea
+ * right now.
  *  -- Cort
  */
 int smp_message[NR_CPUS];
 void smp_message_recv(void)
 {
 	int msg = smp_message[smp_processor_id()];
-	
-	/* clear interrupt */
-	*(volatile unsigned long *)(0xf80000c0) = ~0L;
-	eieio();
+
+	if ( _machine == _MACH_Pmac )
+	{
+		/* clear interrupt */
+		out_be32(PSURGE_INTR, ~0);
+	}
 	
 	/* make sure msg is for us */
 	if ( msg == -1 ) return;
 
 	ipi_count++;
-	/*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/
 	
 	switch( msg )
 	{
@@ -158,12 +167,17 @@
 spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-	if ( _machine != _MACH_Pmac )
+	int i;
+	if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
 		return;
-printk("SMP %d: sending smp message %x\n", current->processor, msg);
-if (smp_processor_id() ) printk("pass from cpu 1\n");
+
 	spin_lock(&mesg_pass_lock);
-#define OTHER (~smp_processor_id() & 1)
+
+	/*
+	 * We assume here that the msg is not -1.  If it is,
+	 * the recipient won't know the message was destined
+	 * for it. -- Cort
+	 */
 	
 	switch( target )
 	{
@@ -171,105 +185,179 @@
 		smp_message[smp_processor_id()] = msg;
 		/* fall through */
 	case MSG_ALL_BUT_SELF:
-		smp_message[OTHER] = msg;
+		for ( i = 0 ; i < smp_num_cpus ; i++ )
+			if ( i != smp_processor_id () )
+				smp_message[i] = msg;
 		break;
 	default:
 		smp_message[target] = msg;
 		break;
 	}
-	/* interrupt secondary processor */
-	*(volatile unsigned long *)(0xf80000c0) = ~0L;
-	eieio();
-	*(volatile unsigned long *)(0xf80000c0) = 0L;
-	eieio();
-	/* interrupt primary */
-	/**(volatile unsigned long *)(0xf3019000);*/
-	spin_unlock(&mesg_pass_lock);	
+	
+	if ( _machine == _MACH_Pmac )
+	{
+		/* interrupt secondary processor */
+		out_be32(PSURGE_INTR, ~0);
+		out_be32(PSURGE_INTR, 0);
+		/*
+		 * Assume for now that the secondary doesn't send
+		 * IPI's -- Cort
+		 */
+		/* interrupt primary */
+		/**(volatile unsigned long *)(0xf3019000);*/
+	}
+	
+	if ( _machine == _MACH_chrp )
+	{
+		/*
+		 * There has to be some way of doing this better -
+		 * perhaps a sent-to-all or send-to-all-but-self
+		 * in the openpic.  This gets us going for now, though.
+		 * -- Cort
+		 */
+		switch ( target )
+		{
+		case MSG_ALL:
+			for ( i = 0 ; i < smp_num_cpus ; i++ )
+				openpic_cause_IPI(i, 0, 0xffffffff );
+			break;
+		case MSG_ALL_BUT_SELF:
+			for ( i = 0 ; i < smp_num_cpus ; i++ )
+				if ( i != smp_processor_id () )
+					openpic_cause_IPI(i, 0,
+			  0xffffffff & ~(1 << smp_processor_id()));
+			break;
+		default:
+			openpic_cause_IPI(target, 0, 1U << target);
+			break;
+		}
+	}
+	
+	spin_unlock(&mesg_pass_lock);
 }
 
 void __init smp_boot_cpus(void)
 {
 	extern struct task_struct *current_set[NR_CPUS];
-	extern void __secondary_start(void);
+	extern void __secondary_start_psurge(void);
 	int i;
 	struct task_struct *p;
 	unsigned long a;
 
         printk("Entering SMP Mode...\n");
-	
+	/* let other processors know to not do certain initialization */
 	first_cpu_booted = 1;
-	/*dcbf(&first_cpu_booted);*/
+	
+	/*
+	 * assume for now that the first cpu booted is
+	 * cpu 0, the master -- Cort
+	 */
+	cpu_callin_map[0] = 1;
+        smp_store_cpu_info(0);
+        active_kernel_processor = 0;
+	current->processor = 0;
 
 	for (i = 0; i < NR_CPUS; i++) {
 		prof_counter[i] = 1;
 		prof_multiplier[i] = 1;
 	}
 
-	cpu_callin_map[0] = 1;
-        smp_store_cpu_info(0);
-        active_kernel_processor = 0;
-	current->processor = 0;
-
 	/*
 	 * XXX very rough, assumes 20 bus cycles to read a cache line,
 	 * timebase increments every 4 bus cycles, 32kB L1 data cache.
 	 */
 	cacheflush_time = 5 * 1024;
 
-	if ( _machine != _MACH_Pmac )
+	if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
 	{
 		printk("SMP not supported on this machine.\n");
 		return;
 	}
 	
-	/* create a process for second processor */
-        kernel_thread(start_secondary, NULL, CLONE_PID);
-	p = task[1];
-	if ( !p )
-		panic("No idle task for secondary processor\n");
-	p->processor = 1;
-	p->has_cpu = 1;
-	current_set[1] = p;
-
-	/* need to flush here since secondary bat's aren't setup */
-	/* XXX ??? */
-	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-	asm volatile("sync");
-
-	/*dcbf((void *)&current_set[1]);*/
-	/* setup entry point of secondary processor */
-	*(volatile unsigned long *)(0xf2800000) =
-		(unsigned long)__secondary_start-KERNELBASE;
-	eieio();
-	/* interrupt secondary to begin executing code */
-	*(volatile unsigned long *)(0xf80000c0) = ~0L;
-	eieio();
-	*(volatile unsigned long *)(0xf80000c0) = 0L;
-	eieio();
+	switch ( _machine )
+	{
+	case _MACH_Pmac:
+		/* assume powersurge board - 2 processors -- Cort */
+		smp_num_cpus = 2; 
+		break;
+	case _MACH_chrp:
+		smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
+				 & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+				OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
+		/* get our processor # - we may not be cpu 0 */
+		printk("SMP %d processors, boot CPU is %d (should be 0)\n",
+		       smp_num_cpus,
+		       10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/);
+		break;
+	}
+
 	/*
-	 * wait to see if the secondary made a callin (is actually up).
-	 * udelay() isn't accurate here since we haven't yet called
-	 * calibrate_delay() so use this value that I found through
-	 * experimentation.  -- Cort
+	 * only check for cpus we know exist.  We keep the callin map
+	 * with cpus at the bottom -- Cort
 	 */
-	for ( i = 1000; i && !cpu_callin_map[1] ; i-- )
-		udelay(100);
+	for ( i = 1 ; i < smp_num_cpus; i++ )
+	{
+		int c;
+		
+		/* create a process for the processor */
+		kernel_thread(start_secondary, NULL, CLONE_PID);
+		p = task[i];
+		if ( !p )
+			panic("No idle task for secondary processor\n");
+		p->processor = i;
+		p->has_cpu = 1;
+		current_set[i] = p;
+
+		/* need to flush here since secondary bats aren't setup */
+		for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+			asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+		asm volatile("sync");
+
+		/* wake up cpus */
+		switch ( _machine )
+		{
+		case _MACH_Pmac:
+			/* setup entry point of secondary processor */
+			*(volatile unsigned long *)(0xf2800000) =
+				(unsigned long)__secondary_start_psurge-KERNELBASE;
+			eieio();
+			/* interrupt secondary to begin executing code */
+			out_be32(PSURGE_INTR, ~0);
+			out_be32(PSURGE_INTR, 0);
+			break;
+		case _MACH_chrp:
+			*(unsigned long *)KERNELBASE = i;
+			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+			break;
+		}
+		
+		/*
+		 * wait to see if the cpu made a callin (is actually up).
+		 * use this value that I found through experimentation.
+		 * -- Cort
+		 */
+		for ( c = 1000; c && !cpu_callin_map[i] ; c-- )
+			udelay(100);
+		
+		if ( cpu_callin_map[i] )
+		{
+			printk("Processor %d found.\n", i);
+			/* this sync's the decr's -- Cort */
+			if ( _machine == _MACH_Pmac )
+				set_dec(decrementer_count);
+		} else {
+			printk("Processor %d is stuck.\n", i);
+		}
+	}
 	
-	if(cpu_callin_map[1]) {
-		printk("Processor %d found.\n", smp_num_cpus);
-		smp_num_cpus++;
-#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
-		set_dec(decrementer_count);
-#endif
-	} else {
-		printk("Processor %d is stuck. \n", smp_num_cpus);
+	if ( _machine == _MACH_Pmac )
+	{
+		/* reset the entry point so if we get another intr we won't
+		 * try to startup again */
+		*(volatile unsigned long *)(0xf2800000) = 0x100;
+		/* send interrupt to other processors to start decr's on all cpus */
+		smp_message_pass(1,0xf0f0, 0, 0);
 	}
-	/* reset the entry point so if we get another intr we won't
-	 * try to startup again */
-	*(volatile unsigned long *)(0xf2800000) = 0x100;
-	/* send interrupt to other processors to start decr's on all cpus */
-	smp_message_pass(1,0xf0f0, 0, 0);
 }
 
 void __init smp_commence(void)
@@ -308,7 +396,6 @@
 	while(!smp_commenced)
 		barrier();
 	__sti();
-	printk("SMP %d: smp_callin done\n", current->processor);
 }
 
 void __init smp_setup(char *str, int *ints)

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