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

Next file: linux/arch/ppc/mm/init.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.2.13/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
@@ -34,8 +34,11 @@
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/gemini.h>
 
 #include "time.h"
+#include "open_pic.h"
+
 int first_cpu_booted = 0;
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
@@ -109,34 +112,8 @@
 	}
 }
 
-/*
- * Dirty hack to get smp message passing working.
- *
- * As it is now, if we're sending two message at the same time
- * 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)
+void smp_message_recv(int msg)
 {
-	int msg = smp_message[smp_processor_id()];
-
-	if ( _machine == _MACH_Pmac )
-	{
-		/* clear interrupt */
-		out_be32(PSURGE_INTR, ~0);
-	}
-	
-	/* make sure msg is for us */
-	if ( msg == -1 ) return;
-
 	ipi_count++;
 	
 	switch( msg )
@@ -145,25 +122,72 @@
 		__cli();
 		while (1) ;
 		break;
-	case MSG_RESCHEDULE: 
+	case MSG_RESCHEDULE:
 		current->need_resched = 1;
 		break;
-	case 0xf0f0: /* syncing time bases - just return */
+	case MSG_INVALIDATE_TLB:
+		_tlbia();
+	case 0xf0f0: /* pmac syncing time bases - just return */
 		break;
 	default:
 		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 		       smp_processor_id(), msg);
 		break;
 	}
+}
+
+/*
+ * As it is now, if we're sending two message at the same time
+ * we have race conditions on Pmac.  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 actual IPI's such as with openpic
+ * rather than this.
+ *  -- Cort
+ */
+int pmac_smp_message[NR_CPUS];
+void pmac_smp_message_recv(void)
+{
+	int msg = pmac_smp_message[smp_processor_id()];
+
+	/* clear interrupt */
+	out_be32(PSURGE_INTR, ~0);
+	
+	/* make sure msg is for us */
+	if ( msg == -1 ) return;
+
+	smp_message_recv(msg);
+
 	/* reset message */
-	smp_message[smp_processor_id()] = -1;
+	pmac_smp_message[smp_processor_id()] = -1;
+}
+
+
+/*
+ * 750's don't broadcast tlb invalidates so
+ * we have to emulate that behavior.
+ *   -- Cort
+ */
+void smp_send_tlb_invalidate(int cpu)
+{
+	if ( (_get_PVR()>>16) == 8 )
+		smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0);
 }
 
 void smp_send_reschedule(int cpu)
 {
-	/* This is only used if `cpu' is running an idle task,
-	   so it will reschedule itself anyway... */
-	/*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+	/*
+	 * This is only used if `cpu' is running an idle task,
+	 * so it will reschedule itself anyway...
+	 *
+	 * This isn't the case anymore since the other CPU could be
+	 * sleeping and won't reschedule until the next interrupt (such
+	 * as the timer).
+	 *  -- Cort
+	 */
+	smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
 }
 
 void smp_send_stop(void)
@@ -171,38 +195,39 @@
 	smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
-spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	int i;
-	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep)) )
+	
+	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
 		return;
 
-	spin_lock(&mesg_pass_lock);
-
-	/*
-	 * 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 )
-	{
-	case MSG_ALL:
-		smp_message[smp_processor_id()] = msg;
-		/* fall through */
-	case MSG_ALL_BUT_SELF:
-		for ( i = 0 ; i < smp_num_cpus ; i++ )
-			if ( i != smp_processor_id () )
-				smp_message[i] = msg;
-		break;
-	default:
-		smp_message[target] = msg;
-		break;
-	}
-	
 	switch (_machine) {
 	case _MACH_Pmac:
+		/*
+		 * IPI's on the Pmac are a hack but without reasonable
+		 * IPI hardware SMP on Pmac is a hack.
+		 *
+		 * We assume here that the msg is not -1.  If it is,
+		 * the recipient won't know the message was destined
+		 * for it. -- Cort
+		 */
+		for ( i = 0; i <= smp_num_cpus ; i++ )
+			pmac_smp_message[i] = -1;
+		switch( target )
+		{
+		case MSG_ALL:
+			pmac_smp_message[smp_processor_id()] = msg;
+			/* fall through */
+		case MSG_ALL_BUT_SELF:
+			for ( i = 0 ; i < smp_num_cpus ; i++ )
+				if ( i != smp_processor_id () )
+					pmac_smp_message[i] = msg;
+			break;
+		default:
+			pmac_smp_message[target] = msg;
+			break;
+		}
 		/* interrupt secondary processor */
 		out_be32(PSURGE_INTR, ~0);
 		out_be32(PSURGE_INTR, 0);
@@ -213,35 +238,27 @@
 		/* interrupt primary */
 		/**(volatile unsigned long *)(0xf3019000);*/
 		break;
-	
 	case _MACH_chrp:
 	case _MACH_prep:
-		/*
-		 * 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
-		 */
+	case _MACH_gemini:
+		/* make sure we're sending something that translates to an IPI */
+		if ( msg > 0x3 )
+			break;
 		switch ( target )
 		{
 		case MSG_ALL:
-			for ( i = 0 ; i < smp_num_cpus ; i++ )
-				openpic_cause_IPI(i, 0, 0xffffffff );
+			openpic_cause_IPI(smp_processor_id(), msg, 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()));
+			openpic_cause_IPI(smp_processor_id(), msg,
+					  0xffffffff & ~(1 << smp_processor_id()));
 			break;
 		default:
-			openpic_cause_IPI(target, 0, 1U << target);
+			openpic_cause_IPI(smp_processor_id(), msg, 1<<target);
 			break;
 		}
 		break;
 	}
-	
-	spin_unlock(&mesg_pass_lock);
 }
 
 void __init smp_boot_cpus(void)
@@ -296,6 +313,10 @@
 			cpu_nr = 2;
 			break;
 		}
+	case _MACH_gemini:
+                cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
+                cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
+		break;
 	default:
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -338,25 +359,16 @@
 		case _MACH_chrp:
 			*(unsigned long *)KERNELBASE = i;
 			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-#if 0
-			device = find_type_devices("cpu");
-			/* assume cpu device list is in order, find the ith cpu */
-			for ( a = i; device && a; device = device->next, a-- )
-				;
-			if ( !device )
-				break;
-			printk( "Starting %s (%lu): ", device->full_name,
-				*(ulong *)get_property(device, "reg", NULL) );
-			call_rtas( "start-cpu", 3, 1, NULL,
-				   *(ulong *)get_property(device, "reg", NULL),
-				   __pa(__secondary_start_chrp), i);
-#endif			
 			break;
 		case _MACH_prep:
 			*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
 			*MotSave_CpusState[1] = CPU_GOOD;
 			printk("CPU1 reset, waiting\n");
 			break;
+		case _MACH_gemini:
+			openpic_init_processor( 1<<i );
+			openpic_init_processor( 0 );
+			break;
 		}
 		
 		/*
@@ -379,6 +391,8 @@
 		}
 	}
 	
+	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+		do_openpic_setup_cpu();
 	if ( _machine == _MACH_Pmac )
 	{
 		/* reset the entry point so if we get another intr we won't
@@ -420,6 +434,13 @@
 #endif
 	init_idle();
 	cpu_callin_map[current->processor] = 1;
+	/*
+	 * Each processor has to do this and this is the best
+	 * place to stick it for now.
+	 *  -- Cort
+	 */
+	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+		do_openpic_setup_cpu();
 	while(!smp_commenced)
 		barrier();
 	__sti();
@@ -437,8 +458,8 @@
 void __init smp_store_cpu_info(int id)
 {
         struct cpuinfo_PPC *c = &cpu_data[id];
-
 	/* assume bogomips are same for everything */
         c->loops_per_sec = loops_per_sec;
         c->pvr = _get_PVR();
 }
+

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