I've been poking at the sparc32 SMP code and I have it to the point where it will run a minimal userland. It is still far from being stable though.
For reference, I started with the SMP patch [0] that wli sent to the list last July. To go along with the attached SMP patch, it needs the spinlock fix [1] from Art Haas, and the attached DEBUGSPINLOCK patch from Tom Callaway.
Here's a list of problems I have seen with it so far: - the scsi driver must be compiled in or it has problems. - when I compiled with gcc 3.3.4, it drops back to the prom with a level 15 interrupt. - from a serial console, init hangs - /proc/interrupts shows 0 interrupts for the 2nd cpu - sun4d still needs fixing
Testing with gcc 3.2.2 and 2 150 MHz HyperSPARCs, if I compile in scsi and leave out all of the networking, I am able to pass "init=/bin/bash" and get a shell everytime.
I am sure there are still areas of bitrot and neglect that remain, so if anyone has any ideas, feel free to share them.
Bob
[0] http://marc.theaimsgroup.com/?l=linux-sparc&m=109105275025491 [1] http://marc.theaimsgroup.com/?l=linux-sparc&m=110806229008323
--- linux-2.6.9/arch/sparc/kernel/sparc_ksyms.c.BAD 2004-12-21 23:40:02.347602755 -0500 +++ linux-2.6.9/arch/sparc/kernel/sparc_ksyms.c 2004-12-22 00:13:53.443829195 -0500 @@ -118,11 +118,12 @@ EXPORT_SYMBOL(kernel_thread); #ifdef CONFIG_SMP EXPORT_SYMBOL(_do_spin_lock); EXPORT_SYMBOL(_do_spin_unlock); -EXPORT_SYMBOL(_spin_trylock); +EXPORT_SYMBOL(_do_spin_trylock); EXPORT_SYMBOL(_do_read_lock); EXPORT_SYMBOL(_do_read_unlock); EXPORT_SYMBOL(_do_write_lock); EXPORT_SYMBOL(_do_write_unlock); +EXPORT_SYMBOL(_do_write_trylock); #endif #else // XXX find what uses (or used) these. --- linux-2.6.9/arch/sparc/lib/debuglocks.c.BAD 2004-12-21 23:38:17.182590267 -0500 +++ linux-2.6.9/arch/sparc/lib/debuglocks.c 2004-12-22 00:10:27.010211875 -0500 @@ -82,7 +82,7 @@ again: lock->owner_pc = (cpu & 3) | (caller & ~3); } -int _spin_trylock(spinlock_t *lock) +int _do_spin_trylock(spinlock_t *lock) { unsigned long val; unsigned long caller; @@ -199,4 +199,27 @@ void _do_write_unlock(rwlock_t *rw) rw->lock = 0; } +int _do_write_trylock (rwlock_t *rw, char *str) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + + STORE_CALLER(caller); + + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if (val) { + barrier(); + return 0; + } + if (rw->lock & ~0xff) { + *(((unsigned char *)&rw->lock)+3) = 0; + barrier(); + return 0; + } + barrier(); + rw->owner_pc = (cpu & 3) | (caller & ~3); + return 1; +} + #endif /* SMP */ --- linux-2.6.9/arch/sparc/Kconfig.BAD 2004-12-21 22:34:04.993212067 -0500 +++ linux-2.6.9/arch/sparc/Kconfig 2004-12-21 22:34:08.358700435 -0500 @@ -83,7 +83,6 @@ config HW_CONSOLE config SMP bool "Symmetric multi-processing support (does not work on sun4/sun4c)" - depends on BROKEN ---help--- This enables support for systems with more than one CPU. If you have a system with only one CPU, say N. If you have a system with more --- linux-2.6.9/include/asm-sparc/spinlock.h.BAD 2004-12-21 23:21:12.779323235 -0500 +++ linux-2.6.9/include/asm-sparc/spinlock.h 2004-12-22 00:12:52.872037507 -0500 @@ -25,10 +25,10 @@ typedef struct _spinlock_debug spinlock_ #define spin_unlock_wait(lp) do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock)) extern void _do_spin_lock(spinlock_t *lock, char *str); -extern int _spin_trylock(spinlock_t *lock); +extern int _do_spin_trylock(spinlock_t *lock); extern void _do_spin_unlock(spinlock_t *lock); -#define _raw_spin_trylock(lp) _spin_trylock(lp) +#define _raw_spin_trylock(lp) _do_spin_trylock(lp) #define _raw_spin_lock(lock) _do_spin_lock(lock, "spin_lock") #define _raw_spin_unlock(lock) _do_spin_unlock(lock) @@ -48,6 +48,7 @@ extern void _do_read_lock(rwlock_t *rw, extern void _do_read_unlock(rwlock_t *rw, char *str); extern void _do_write_lock(rwlock_t *rw, char *str); extern void _do_write_unlock(rwlock_t *rw); +extern int _do_write_trylock(rwlock_t *rw, char *str); #define _raw_read_lock(lock) \ do { unsigned long flags; \ @@ -77,6 +78,15 @@ do { unsigned long flags; \ local_irq_restore(flags); \ } while(0) +#define _raw_write_trylock(lock) \ +({ unsigned long flags; \ + int val; \ + local_irq_save(flags); \ + val = _do_write_trylock(lock, "write_trylock"); \ + local_irq_restore(flags); \ + val; \ +}) + #else /* !CONFIG_DEBUG_SPINLOCK */ typedef unsigned char spinlock_t;
--- linux-2.6.11-rc3-clean/include/asm-sparc/smp.h 2004-10-18 16:53:43.000000000 -0500 +++ linux-2.6.11-rc3/include/asm-sparc/smp.h 2005-02-12 12:12:19.000000000 -0600 @@ -81,16 +81,9 @@ return 0; } -extern __volatile__ int __cpu_number_map[NR_CPUS]; -extern __volatile__ int __cpu_logical_map[NR_CPUS]; - extern __inline__ int cpu_logical_map(int cpu) { - return __cpu_logical_map[cpu]; -} -extern __inline__ int cpu_number_map(int cpu) -{ - return __cpu_number_map[cpu]; + return cpu; } extern __inline__ int hard_smp4m_processor_id(void) --- linux-2.6.11-rc3-clean/include/asm-sparc/spinlock.h 2005-02-06 20:32:54.000000000 -0600 +++ linux-2.6.11-rc3/include/asm-sparc/spinlock.h 2005-02-12 23:06:56.000000000 -0600 @@ -101,7 +101,7 @@ barrier(); \ } while(*((volatile unsigned char *)lock)) -extern __inline__ void _raw_spin_lock(spinlock_t *lock) +static inline void _raw_spin_lock(spinlock_t *lock) { __asm__ __volatile__( "\n1:\n\t" @@ -121,7 +121,7 @@ : "g2", "memory", "cc"); } -extern __inline__ int _raw_spin_trylock(spinlock_t *lock) +static inline int _raw_spin_trylock(spinlock_t *lock) { unsigned int result; __asm__ __volatile__("ldstub [%1], %0" @@ -131,7 +131,7 @@ return (result == 0); } -extern __inline__ void _raw_spin_unlock(spinlock_t *lock) +static inline void _raw_spin_unlock(spinlock_t *lock) { __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); } @@ -174,7 +174,7 @@ * * Unfortunately this scheme limits us to ~16,000,000 cpus. */ -extern __inline__ void _read_lock(rwlock_t *rw) +static inline void __read_lock(rwlock_t *rw) { register rwlock_t *lp asm("g1"); lp = rw; @@ -190,11 +190,11 @@ #define _raw_read_lock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - _read_lock(lock); \ + __read_lock(lock); \ local_irq_restore(flags); \ } while(0) -extern __inline__ void _read_unlock(rwlock_t *rw) +static inline void __read_unlock(rwlock_t *rw) { register rwlock_t *lp asm("g1"); lp = rw; @@ -210,11 +210,11 @@ #define _raw_read_unlock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - _read_unlock(lock); \ + __read_unlock(lock); \ local_irq_restore(flags); \ } while(0) -extern __inline__ void _raw_write_lock(rwlock_t *rw) +static inline void _raw_write_lock(rwlock_t *rw) { register rwlock_t *lp asm("g1"); lp = rw; @@ -227,11 +227,33 @@ : "g2", "g4", "memory", "cc"); } +static inline int _raw_write_trylock(rwlock_t *rw) +{ + int val; + __asm__ __volatile__( + "ldstub [%1 + 3], %0\n\t" + "orcc %0, 0x0, %%g0\n\t" + "bne 1f\n\t" + " nop\n\t" + "ld [%1], %0\n\t" + "andncc %0, 0xff, %0\n\t" + "bne,a 1f\n\t" + " stb %%g0, [%1 + 3]\n" + "1:" + : "=&r" (val) + : "r" (rw) + : "memory", "cc"); + + /* on success, val is zero and return true */ + return (val == 0); +} + #define _raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) #endif /* CONFIG_DEBUG_SPINLOCK */ #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) #endif /* !(__ASSEMBLY__) */ Only in linux-2.6.11-rc3/arch/sparc/boot: btfix.S Only in linux-2.6.11-rc3/arch/sparc/boot: image diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/irq.c linux-2.6.11-rc3/arch/sparc/kernel/irq.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/irq.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/irq.c 2005-02-12 12:16:35.000000000 -0600 @@ -21,6 +21,7 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/slab.h> #include <linux/random.h> #include <linux/init.h> @@ -154,8 +155,11 @@ void (*sparc_init_timers)(irqreturn_t (* struct irqaction static_irqaction[MAX_STATIC_ALLOC]; int static_irq_count; -struct irqaction *irq_action[NR_IRQS] = { - [0 ... (NR_IRQS-1)] = NULL +struct { + struct irqaction *action; + int flags; +} sparc_irq[NR_IRQS] = { + [0 ... (NR_IRQS-1)] = { NULL, 0 } }; /* Used to protect the IRQ action lists */ @@ -177,7 +181,7 @@ int show_interrupts(struct seq_file *p, } spin_lock_irqsave(&irq_action_lock, flags); if (i < NR_IRQS) { - action = *(i + irq_action); + action = sparc_irq[i].action; if (!action) goto out_unlock; seq_printf(p, "%3d: ", i); @@ -187,7 +191,7 @@ int show_interrupts(struct seq_file *p, for (j = 0; j < NR_CPUS; j++) { if (cpu_online(j)) seq_printf(p, "%10u ", - kstat_cpu(cpu_logical_map(j)).irqs[i]); + kstat_cpu(j).irqs[i]); } #endif seq_printf(p, " %c %s", @@ -226,7 +230,7 @@ void free_irq(unsigned int irq, void *de spin_lock_irqsave(&irq_action_lock, flags); - action = *(cpu_irq + irq_action); + action = sparc_irq[cpu_irq].action; if (!action->handler) { printk("Trying to free free IRQ%d\n",irq); @@ -259,7 +263,7 @@ void free_irq(unsigned int irq, void *de if (action && tmp) tmp->next = action->next; else - *(cpu_irq + irq_action) = action->next; + sparc_irq[cpu_irq].action = action->next; spin_unlock_irqrestore(&irq_action_lock, flags); @@ -269,7 +273,7 @@ void free_irq(unsigned int irq, void *de kfree(action); - if (!(*(cpu_irq + irq_action))) + if (!sparc_irq[cpu_irq].action) disable_irq(irq); out_unlock: @@ -288,8 +292,8 @@ EXPORT_SYMBOL(free_irq); #ifdef CONFIG_SMP void synchronize_irq(unsigned int irq) { - printk("synchronize_irq says: implement me!\n"); - BUG(); + while (sparc_irq[irq].flags & IRQ_INPROGRESS) + cpu_relax(); } #endif /* SMP */ @@ -300,7 +304,7 @@ void unexpected_irq(int irq, void *dev_i unsigned int cpu_irq; cpu_irq = irq & (NR_IRQS - 1); - action = *(cpu_irq + irq_action); + action = sparc_irq[cpu_irq].action; printk("IO device interrupt, irq = %d\n", irq); printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, @@ -326,12 +330,13 @@ void handler_irq(int irq, struct pt_regs irq_enter(); disable_pil_irq(irq); + sparc_irq[irq].flags |= IRQ_INPROGRESS; #ifdef CONFIG_SMP /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */ if(irq < 10) smp4m_irq_rotate(cpu); #endif - action = *(irq + irq_action); + action = sparc_irq[irq].action; kstat_cpu(cpu).irqs[irq]++; do { if (!action || !action->handler) @@ -339,6 +344,7 @@ void handler_irq(int irq, struct pt_regs action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + sparc_irq[irq].flags &= ~IRQ_INPROGRESS; enable_pil_irq(irq); irq_exit(); } @@ -390,7 +396,7 @@ int request_fast_irq(unsigned int irq, spin_lock_irqsave(&irq_action_lock, flags); - action = *(cpu_irq + irq_action); + action = sparc_irq[cpu_irq].action; if(action) { if(action->flags & SA_SHIRQ) panic("Trying to register fast irq when already shared.\n"); @@ -453,7 +459,7 @@ int request_fast_irq(unsigned int irq, action->dev_id = NULL; action->next = NULL; - *(cpu_irq + irq_action) = action; + sparc_irq[cpu_irq].action = action; enable_irq(irq); @@ -491,7 +497,7 @@ int request_irq(unsigned int irq, spin_lock_irqsave(&irq_action_lock, flags); - action = *(cpu_irq + irq_action); + action = sparc_irq[cpu_irq].action; if (action) { if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { for (tmp = action; tmp->next; tmp = tmp->next); @@ -536,7 +542,7 @@ int request_irq(unsigned int irq, if (tmp) tmp->next = action; else - *(cpu_irq + irq_action) = action; + sparc_irq[cpu_irq].action = action; enable_irq(irq); diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/smp.c linux-2.6.11-rc3/arch/sparc/kernel/smp.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/smp.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/smp.c 2005-02-12 23:17:07.000000000 -0600 @@ -48,6 +48,7 @@ unsigned long cache_decay_ticks = 100; cpumask_t cpu_online_map = CPU_MASK_NONE; cpumask_t phys_cpu_present_map = CPU_MASK_NONE; +cpumask_t smp_commenced_mask = CPU_MASK_NONE; /* The only guaranteed locking primitive available on all Sparc * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically @@ -60,11 +61,6 @@ cpumask_t phys_cpu_present_map = CPU_MAS /* Used to make bitops atomic */ unsigned char bitops_spinlock = 0; -volatile unsigned long ipi_count; - -volatile int smp_process_available=0; -volatile int smp_commenced = 0; - void __init smp_store_cpu_info(int id) { int cpu_node; @@ -82,6 +78,20 @@ void __init smp_store_cpu_info(int id) void __init smp_cpus_done(unsigned int max_cpus) { + extern void smp4m_smp_done(void); + unsigned long bogosum = 0; + int i; + + for_each_online_cpu(i) + bogosum += cpu_data(i).udelay_val; + + printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + num_online_cpus(), + bogosum/(500000/HZ), + (bogosum/(5000/HZ))%100); + + BUG_ON(sparc_cpu_model != sun4m); + smp4m_smp_done(); } void cpu_panic(void) @@ -92,17 +102,6 @@ void cpu_panic(void) struct linux_prom_registers smp_penguin_ctable __initdata = { 0 }; -void __init smp_boot_cpus(void) -{ - extern void smp4m_boot_cpus(void); - extern void smp4d_boot_cpus(void); - - if (sparc_cpu_model == sun4m) - smp4m_boot_cpus(); - else - smp4d_boot_cpus(); -} - void smp_send_reschedule(int cpu) { /* See sparc64 */ @@ -256,20 +255,65 @@ int setup_profiling_timer(unsigned int m return 0; } -void __init smp_prepare_cpus(unsigned int maxcpus) +void __init smp_prepare_cpus(unsigned int max_cpus) { + extern void smp4m_boot_cpus(); + int i, mid, ncpus, extra; + + BUG_ON(sparc_cpu_model != sun4m); + printk("Entering SMP Mode...\n"); + + local_irq_enable(); // is this needed ? + + ncpus = 1; + extra = 0; + for (i=0; !cpu_find_by_instance(i, NULL, &mid); i++) { + if (mid == boot_cpu_id) + continue; + if (mid < NR_CPUS && ncpus++ < max_cpus) + cpu_set(mid, phys_cpu_present_map); + else + extra++; + } + if (max_cpus >= NR_CPUS && extra) + printk("Warning: NR_CPUS is too low to start all cpus\n"); + +// current_thread_info()->cpu = boot_cpu_id; + smp_store_cpu_info(boot_cpu_id); + + smp4m_boot_cpus(); } void __devinit smp_prepare_boot_cpu(void) { - current_thread_info()->cpu = hard_smp_processor_id(); - cpu_set(smp_processor_id(), cpu_online_map); - cpu_set(smp_processor_id(), phys_cpu_present_map); + int cpuid = hard_smp_processor_id(); + + if (cpuid >= NR_CPUS) { + prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); + prom_halt(); + } + else if (cpuid != 0) + printk("boot cpu id != 0, this could work but is untested\n"); + + current_thread_info()->cpu = cpuid; + cpu_set(cpuid, cpu_online_map); + cpu_set(cpuid, phys_cpu_present_map); } int __devinit __cpu_up(unsigned int cpu) { - panic("smp doesn't work\n"); + extern int smp4m_boot_one_cpu(int); + int ret; + + BUG_ON(sparc_cpu_model != sun4m); + ret = smp4m_boot_one_cpu(cpu); + + if (!ret) { + cpu_set(cpu, smp_commenced_mask); + while (!cpu_online(cpu)) + mb(); + } + return ret; } void smp_bogo(struct seq_file *m) diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/sparc_ksyms.c linux-2.6.11-rc3/arch/sparc/kernel/sparc_ksyms.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/sparc_ksyms.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/sparc_ksyms.c 2005-02-12 22:52:05.000000000 -0600 @@ -90,6 +90,9 @@ extern void ___set_bit(void); extern void ___clear_bit(void); extern void ___change_bit(void); +/* Per-CPU information table */ +EXPORT_PER_CPU_SYMBOL(__cpu_data); + /* Alias functions whose names begin with "." and export the aliases. * The module references will be fixed up by module_frob_arch_sections. */ @@ -148,9 +151,9 @@ EXPORT_SYMBOL(___change_bit); /* IRQ implementation. */ EXPORT_SYMBOL(synchronize_irq); -/* Misc SMP information */ -EXPORT_SYMBOL(__cpu_number_map); -EXPORT_SYMBOL(__cpu_logical_map); +/* CPU online map and active count. */ +EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(phys_cpu_present_map); #endif EXPORT_SYMBOL(__udelay); diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4d_irq.c linux-2.6.11-rc3/arch/sparc/kernel/sun4d_irq.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4d_irq.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/sun4d_irq.c 2005-02-12 12:12:19.000000000 -0600 @@ -14,6 +14,7 @@ #include <linux/sched.h> #include <linux/ptrace.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/slab.h> #include <linux/random.h> #include <linux/init.h> @@ -54,7 +55,8 @@ unsigned char cpu_leds[32]; unsigned char sbus_tid[32]; #endif -extern struct irqaction *irq_action[]; +//extern struct irqaction *irq_action[]; +extern struct { struct irqaction *action; int flags; } sparc_irq[]; extern spinlock_t irq_action_lock; struct sbus_action { @@ -88,7 +90,7 @@ int show_sun4d_interrupts(struct seq_fil if (i < NR_IRQS) { sbusl = pil_to_sbus[i]; if (!sbusl) { - action = *(i + irq_action); + action = sparc_irq[i].action; if (!action) goto out_unlock; } else { @@ -145,7 +147,7 @@ void sun4d_free_irq(unsigned int irq, vo spin_lock_irqsave(&irq_action_lock, flags); if (irq < 15) - actionp = irq + irq_action; + actionp = &(sparc_irq[irq].action); else actionp = &(sbus_actions[irq - (1 << 5)].action); action = *actionp; @@ -212,9 +214,10 @@ void sun4d_handler_irq(int irq, struct p cc_set_iclr(1 << irq); irq_enter(); + sparc_irq[irq].flags |= IRQ_INPROGRESS; kstat_cpu(cpu).irqs[irq]++; if (!sbusl) { - action = *(irq + irq_action); + action = sparc_irq[irq].action; if (!action) unexpected_irq(irq, NULL, regs); do { @@ -252,6 +255,7 @@ void sun4d_handler_irq(int irq, struct p } } } + sparc_irq[irq].flags &= ~IRQ_INPROGRESS; irq_exit(); } @@ -297,7 +301,7 @@ int sun4d_request_irq(unsigned int irq, if (irq >= (1 << 5)) actionp = &(sbus_actions[irq - (1 << 5)].action); else - actionp = irq + irq_action; + actionp = &(sparc_irq[irq].action); action = *actionp; if (action) { diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4d_smp.c linux-2.6.11-rc3/arch/sparc/kernel/sun4d_smp.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4d_smp.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/sun4d_smp.c 2005-02-12 12:12:19.000000000 -0600 @@ -54,7 +54,9 @@ extern volatile int __cpu_number_map[NR_ extern volatile int __cpu_logical_map[NR_CPUS]; extern volatile unsigned long ipi_count; extern volatile int smp_process_available; -extern volatile int smp_commenced; + +extern cpumask_t smp_commenced_mask; + extern int __smp4d_processor_id(void); /* #define SMP_DEBUG */ @@ -137,7 +139,7 @@ void __init smp4d_callin(void) local_irq_enable(); /* We don't allow PIL 14 yet */ - while(!smp_commenced) + while (!cpu_isset(cpuid, smp_commenced_mask)) barrier(); spin_lock_irqsave(&sun4d_imsk_lock, flags); diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4m_smp.c linux-2.6.11-rc3/arch/sparc/kernel/sun4m_smp.c --- linux-2.6.11-rc3-clean/arch/sparc/kernel/sun4m_smp.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/kernel/sun4m_smp.c 2005-02-12 23:24:40.000000000 -0600 @@ -40,16 +40,11 @@ extern ctxd_t *srmmu_ctx_table_phys; extern void calibrate_delay(void); extern volatile int smp_processors_ready; -extern int smp_num_cpus; -extern int smp_threads_ready; extern volatile unsigned long cpu_callin_map[NR_CPUS]; extern unsigned char boot_cpu_id; -extern int smp_activated; -extern volatile int __cpu_number_map[NR_CPUS]; -extern volatile int __cpu_logical_map[NR_CPUS]; -extern volatile unsigned long ipi_count; -extern volatile int smp_process_available; -extern volatile int smp_commenced; + +extern cpumask_t smp_commenced_mask; + extern int __smp4m_processor_id(void); /*#define SMP_DEBUG*/ @@ -78,8 +73,6 @@ void __init smp4m_callin(void) local_flush_cache_all(); local_flush_tlb_all(); - set_irq_udt(boot_cpu_id); - /* Get our local ticker going. */ smp_setup_percpu_timer(); @@ -96,7 +89,7 @@ void __init smp4m_callin(void) * to call the scheduler code. */ /* Allow master to continue. */ - swap((unsigned long *)&cpu_callin_map[cpuid], 1); + swap(&cpu_callin_map[cpuid], 1); local_flush_cache_all(); local_flush_tlb_all(); @@ -112,13 +105,12 @@ void __init smp4m_callin(void) atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - while(!smp_commenced) - barrier(); - - local_flush_cache_all(); - local_flush_tlb_all(); + while (!cpu_isset(cpuid, smp_commenced_mask)) + mb(); local_irq_enable(); + + cpu_set(cpuid, cpu_online_map); } extern void init_IRQ(void); @@ -135,45 +127,23 @@ extern unsigned long trapbase_cpu3[]; void __init smp4m_boot_cpus(void) { - int cpucount = 0; - int i, mid; - - printk("Entering SMP Mode...\n"); - - local_irq_enable(); - cpus_clear(cpu_present_map); - - for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) - cpu_set(mid, cpu_present_map); - - for(i=0; i < NR_CPUS; i++) { - __cpu_number_map[i] = -1; - __cpu_logical_map[i] = -1; - } - - __cpu_number_map[boot_cpu_id] = 0; - __cpu_logical_map[0] = boot_cpu_id; - current_thread_info()->cpu = boot_cpu_id; - - smp_store_cpu_info(boot_cpu_id); - set_irq_udt(boot_cpu_id); smp_setup_percpu_timer(); local_flush_cache_all(); - if(cpu_find_by_instance(1, NULL, NULL)) - return; /* Not an MP box. */ - for(i = 0; i < NR_CPUS; i++) { - if(i == boot_cpu_id) - continue; +} - if (cpu_isset(i, cpu_present_map)) { +int smp4m_boot_one_cpu(int i) +{ extern unsigned long sun4m_cpu_startup; unsigned long *entry = &sun4m_cpu_startup; struct task_struct *p; int timeout; + int cpu_node; + + cpu_find_by_mid(i, &cpu_node); + /* Cook up an idler for this guy. */ p = fork_idle(i); - cpucount++; current_set[i] = p->thread_info; /* See trampoline.S for details... */ entry += ((i-1) * 3); @@ -190,7 +160,7 @@ void __init smp4m_boot_cpus(void) /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); local_flush_cache_all(); - prom_startcpu(cpu_data(i).prom_node, + prom_startcpu(cpu_node, &smp_penguin_ctable, 0, (char *)entry); /* wheee... it's going... */ @@ -199,40 +169,19 @@ void __init smp4m_boot_cpus(void) break; udelay(200); } - if(cpu_callin_map[i]) { - /* Another "Red Snapper". */ - __cpu_number_map[i] = i; - __cpu_logical_map[i] = i; - } else { - cpucount--; - printk("Processor %d is stuck.\n", i); - } - } - if(!(cpu_callin_map[i])) { - cpu_clear(i, cpu_present_map); - __cpu_number_map[i] = -1; - } + if (!cpu_callin_map[i]) { + printk("Processor %d is stuck.\n", i); + return -ENODEV; } + return 0; +} + +void __init smp4m_smp_done(void) +{ local_flush_cache_all(); - if(cpucount == 0) { - printk("Error: only one Processor found.\n"); - cpu_present_map = cpumask_of_cpu(smp_processor_id()); - } else { - unsigned long bogosum = 0; - for(i = 0; i < NR_CPUS; i++) { - if (cpu_isset(i, cpu_present_map)) - bogosum += cpu_data(i).udelay_val; - } - printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", - cpucount + 1, - bogosum/(500000/HZ), - (bogosum/(5000/HZ))%100); - smp_activated = 1; - smp_num_cpus = cpucount + 1; - } /* Free unneeded trap tables */ - if (!cpu_isset(i, cpu_present_map)) { + if (!cpu_isset(1, cpu_present_map)) { ClearPageReserved(virt_to_page(trapbase_cpu1)); set_page_count(virt_to_page(trapbase_cpu1), 1); free_page((unsigned long)trapbase_cpu1); @@ -292,7 +241,7 @@ void smp4m_message_pass(int target, int smp_cpu_in_msg[me]++; if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) { - mask = cpu_present_map; + mask = cpu_online_map; if(target == MSG_ALL_BUT_SELF) cpu_clear(me, mask); for(i = 0; i < 4; i++) { @@ -328,7 +277,7 @@ void smp4m_cross_call(smpfunc_t func, un unsigned long arg3, unsigned long arg4, unsigned long arg5) { if(smp_processors_ready) { - register int ncpus = smp_num_cpus; + register int ncpus = NR_CPUS; //smp_num_cpus; unsigned long flags; spin_lock_irqsave(&cross_call_lock, flags); @@ -343,7 +292,7 @@ void smp4m_cross_call(smpfunc_t func, un /* Init receive/complete mapping, plus fire the IPI's off. */ { - cpumask_t mask = cpu_present_map; + cpumask_t mask = cpu_online_map; register int i; cpu_clear(smp_processor_id(), mask); Only in linux-2.6.11-rc3/arch/sparc/kernel: vmlinux.lds diff -X dontdiff -urp linux-2.6.11-rc3-clean/arch/sparc/mm/srmmu.c linux-2.6.11-rc3/arch/sparc/mm/srmmu.c --- linux-2.6.11-rc3-clean/arch/sparc/mm/srmmu.c 2005-02-06 20:30:54.000000000 -0600 +++ linux-2.6.11-rc3/arch/sparc/mm/srmmu.c 2005-02-12 13:40:45.000000000 -0600 @@ -1417,6 +1417,7 @@ static void __init init_vac_layout(void) max_size = vac_cache_size; if(vac_line_size < min_line_size) min_line_size = vac_line_size; + // FIXME: cpus not contiguous!! cpu++; if (cpu >= NR_CPUS || !cpu_online(cpu)) break;