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
- Lines: 360
- Date:
Wed Nov 8 23:00:34 2000
- Orig file:
v2.2.17/arch/ppc/kernel/smp.c
- Orig date:
Sat Sep 9 18:42:33 2000
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)