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;