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

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

diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
@@ -8,6 +8,8 @@
  *
  * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
  * (troy@blacklablinux.com, hozer@drgw.net)
+ * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP 
+ * by Troy Benjegerdes (hozer@drgw.net)
  */
 
 #include <linux/kernel.h>
@@ -37,6 +39,7 @@
 #include <asm/gemini.h>
 #include <asm/residual.h>
 #include <asm/time.h>
+#include <asm/feature.h>
 #include "open_pic.h"
 
 int first_cpu_booted = 0;
@@ -46,7 +49,8 @@
 struct cpuinfo_PPC cpu_data[NR_CPUS];
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 volatile unsigned char active_kernel_processor = NO_PROC_ID;	/* Processor holding kernel spinlock		*/
-volatile unsigned long ipi_count;
+atomic_t ipi_recv;
+atomic_t ipi_sent;
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
@@ -64,6 +68,9 @@
 extern unsigned long *MotSave_SmpIar;
 extern unsigned char *MotSave_CpusState[2];
 
+/* l2 cache stuff for dual G4 macs */
+extern void core99_init_l2(void);
+ 
 /* register for interrupting the secondary processor on the powersurge */
 #define PSURGE_INTR	((volatile unsigned *)0xf80000c0)
 
@@ -114,7 +121,7 @@
 
 void smp_message_recv(int msg)
 {
-	ipi_count++;
+ 	atomic_inc(&ipi_recv);
 	
 	switch( msg )
 	{
@@ -136,6 +143,7 @@
 	}
 }
 
+#ifdef CONFIG_POWERMAC
 /*
  * 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
@@ -147,10 +155,10 @@
  * rather than this.
  *  -- Cort
  */
-int pmac_smp_message[NR_CPUS];
-void pmac_smp_message_recv(void)
+int psurge_smp_message[NR_CPUS];
+void psurge_smp_message_recv(void)
 {
-	int msg = pmac_smp_message[smp_processor_id()];
+	int msg = psurge_smp_message[smp_processor_id()];
 
 	/* clear interrupt */
 	out_be32(PSURGE_INTR, ~0);
@@ -161,9 +169,9 @@
 	smp_message_recv(msg);
 
 	/* reset message */
-	pmac_smp_message[smp_processor_id()] = -1;
+	psurge_smp_message[smp_processor_id()] = -1;
 }
-
+#endif /* powermac */
 
 /*
  * 750's don't broadcast tlb invalidates so
@@ -195,49 +203,65 @@
 	smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+#ifdef CONFIG_POWERMAC
+static void psurge_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	int i;
 	
+	/*
+	 * 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++ )
+		psurge_smp_message[i] = -1;
+	switch( target )
+	{
+	case MSG_ALL:
+		psurge_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 () )
+				psurge_smp_message[i] = msg;
+		break;
+	default:
+		psurge_smp_message[target] = msg;
+		break;
+	}
+	/* 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
+	 * Could be fixed with 2.4 code from Paulus -- BenH
+	 */
+	/* interrupt primary */
+	/**(volatile unsigned long *)(0xf3019000);*/
+}
+#endif /* powermac */
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ 	atomic_inc(&ipi_sent);
+
 	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
 		return;
 
 	switch (_machine) {
+#ifdef CONFIG_POWERMAC
 	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;
+		/* Hack, 2.4 does it cleanly */
+		if (OpenPIC == NULL) {
+			psurge_message_pass(target, msg, data, wait);
 			break;
-		}
-		/* 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);*/
-		break;
+		} 
+		/* else fall through and do something sane --Troy */
+#endif
 	case _MACH_chrp:
 	case _MACH_prep:
 	case _MACH_gemini:
@@ -261,6 +285,52 @@
 	}
 }
 
+#ifdef CONFIG_POWERMAC
+static void pmac_core99_kick_cpu(int nr)
+{
+	extern void __secondary_start_psurge(void);
+
+	unsigned long save_int;
+	unsigned long flags;
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x500));
+
+	if (nr != 1)
+		return;
+
+	__save_flags(flags);
+	__cli();
+	
+	/* Save EE vector */
+	save_int = *vector;
+	
+	/* Setup fake EE vector that does	  
+	 *   b __secondary_start_psurge - KERNELBASE
+	 */   
+	*vector = 0x48000002 +
+		((unsigned long)__secondary_start_psurge - 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();
+	
+	/* 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,
+	 * ideally, all that crap will be done in prom.c and the CPU left
+	 * in a RAM-based wait loop like CHRP.
+	 */
+	mdelay(1);
+	
+	/* Restore our exception vector */
+	*vector = save_int;
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+	__restore_flags(flags);
+}
+#endif /* powermac */
+
 void __init smp_boot_cpus(void)
 {
 	extern struct task_struct *current_set[NR_CPUS];
@@ -297,15 +367,21 @@
 
 	switch ( _machine )
 	{
+#ifdef CONFIG_POWERMAC
 	case _MACH_Pmac:
-		/* assume powersurge board - 2 processors -- Cort */
+		/* assum e powersurge board - 2 processors -- Cort */
+		/* or a dual G4 -- Troy */
 		cpu_nr = 2;
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
 	case _MACH_chrp:
 		cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
 				 & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
 				OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
  	case _MACH_prep:
  		/* assume 2 for now == fix later -- Johnnie */
 		if ( mot_multi )
@@ -313,10 +389,13 @@
 			cpu_nr = 2;
 			break;
 		}
+#endif
+#ifdef CONFIG_GEMINI
 	case _MACH_gemini:
                 cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
                 cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
 		break;
+#endif
 	default:
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -347,30 +426,41 @@
 		/* wake up cpus */
 		switch ( _machine )
 		{
+#ifdef CONFIG_POWERMAC
 		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);
+			if (OpenPIC == NULL) {
+				/* 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);
+			} else
+				pmac_core99_kick_cpu(i);
 			break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
 		case _MACH_chrp:
 			*(unsigned long *)KERNELBASE = i;
 			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
 			break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
 		case _MACH_prep:
 			*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
 			*MotSave_CpusState[1] = CPU_GOOD;
 			printk("CPU1 reset, waiting\n");
 			break;
+#endif
+#ifdef CONFIG_GEMINI
 		case _MACH_gemini:
 			openpic_init_processor( 1<<i );
 			openpic_init_processor( 0 );
 			break;
+#endif
 		}
-		
+
 		/*
 		 * wait to see if the cpu made a callin (is actually up).
 		 * use this value that I found through experimentation.
@@ -391,9 +481,9 @@
 		}
 	}
 	
-	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+	if (OpenPIC)
 		do_openpic_setup_cpu();
-	if ( _machine == _MACH_Pmac )
+	else if ( _machine == _MACH_Pmac )
 	{
 		/* reset the entry point so if we get another intr we won't
 		 * try to startup again */
@@ -439,10 +529,17 @@
 	 * place to stick it for now.
 	 *  -- Cort
 	 */
-	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+	if (OpenPIC) {
 		do_openpic_setup_cpu();
+#ifdef CONFIG_POWERMAC
+ 		if ( _machine == _MACH_Pmac )
+ 			core99_init_l2();
+#endif
+ 	}
+#ifdef CONFIG_GEMINI
 	if ( _machine == _MACH_gemini )
 	        gemini_init_l2();
+#endif
 	while(!smp_commenced)
 		barrier();
 	__sti();
@@ -461,7 +558,7 @@
 {
         struct cpuinfo_PPC *c = &cpu_data[id];
 	/* assume bogomips are same for everything */
-        c->loops_per_sec = loops_per_sec;
+        c->loops_per_jiffy = loops_per_jiffy;
         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)