summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel/smp.c')
-rw-r--r--arch/ppc/kernel/smp.c249
1 files changed, 170 insertions, 79 deletions
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index ba505e133..c38fc3108 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,10 +1,13 @@
/*
- * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
*
* Smp support for ppc.
*
* Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
* deal of code from the sparc and intel versions.
+ *
+ * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
+ * (troy@microux.com, hozer@drgw.net)
*/
#include <linux/kernel.h>
@@ -18,6 +21,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 +33,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 +47,6 @@ volatile unsigned long ipi_count;
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 +55,10 @@ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
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 +107,33 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
/*
* 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 +170,17 @@ void smp_send_stop(void)
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 +188,180 @@ if (smp_processor_id() ) printk("pass from cpu 1\n");
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;
+ cpu_callin_map[1] = 0;
+ 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 +400,6 @@ void __init smp_callin(void)
while(!smp_commenced)
barrier();
__sti();
- printk("SMP %d: smp_callin done\n", current->processor);
}
void __init smp_setup(char *str, int *ints)