From db7d4daea91e105e3859cf461d7e53b9b77454b2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 13 Jun 1999 16:29:25 +0000 Subject: Merge with Linux 2.2.8. --- arch/ppc/kernel/smp.c | 249 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 170 insertions(+), 79 deletions(-) (limited to 'arch/ppc/kernel/smp.c') 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 @@ -18,6 +21,7 @@ #define __KERNEL_SYSCALLS__ #include #include +#include #include #include @@ -29,9 +33,10 @@ #include #include #include +#include #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 *)¤t_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) -- cgit v1.2.3