diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index 66d95c741917de4ec824fad9cc0554500f33ae69..4bf512ebbe5500d3d98493e4e6cf2af1c5409487 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -24,6 +24,10 @@
 
 
 
+/* use IRQMP for inter-processor interrupt */
+#define LEON3_IPIRQ		12
+
+
 #define ASI_LEON3_SYSCTRL	0x02
 
 #define ASI_LEON3_SYSCTRL_CCR	0x00
diff --git a/arch/sparc/include/asm/switch_to.h b/arch/sparc/include/asm/switch_to.h
index cb6185c8f5f94e448a8e1d8fecc9a0423c9426eb..3b0708162515a75a431018d09f936586edb81dcd 100644
--- a/arch/sparc/include/asm/switch_to.h
+++ b/arch/sparc/include/asm/switch_to.h
@@ -187,7 +187,7 @@ __asm__ __volatile__(							\
 	" nop\n\t"						\
 	"here:\n\t"						\
 	:							\
-	: "r" (&(current_set[leon3_cpuid()])),			\
+	: "r" (&(current_set[smp_cpu_id()])),			\
 	  "r" (&(next->thread_info)),				\
 	  "i" (TI_KSP),						\
 	  "i" (TI_KPC),						\
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 67a11861fa4da7915f174f4bedf6531125d5ea2e..69b6ca406dbcf45000aa577f8d82b94154867266 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -27,6 +27,7 @@ obj-y += stack.o
 obj-y += traps/data_access_exception_trap.o
 obj-y += traps/data_access_exception.o
 obj-y += irq.o
+obj-y += smp.o
 obj-y += time.o
 obj-y += clockevent.o
 
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 8a1173585a5dec524eb67b3bb276a60676be965b..bb66021997721ea2da54522da462070bcd981994 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -461,7 +461,7 @@ static void leon_mask_irq(unsigned int irq, int cpu)
  * @param cpu the cpu for which the interrupt is to be enabled
  */
 
-static void leon_enable_irq(unsigned int irq, int cpu)
+void leon_enable_irq(unsigned int irq, int cpu)
 {
 	leon_clear_irq(irq);
 
@@ -476,7 +476,7 @@ static void leon_enable_irq(unsigned int irq, int cpu)
  * @param cpu the cpu for which the interrupt is to be disabled
  */
 
-static void leon_disable_irq(unsigned int irq, int cpu)
+void leon_disable_irq(unsigned int irq, int cpu)
 {
 	leon_clear_irq(irq);
 
@@ -484,6 +484,28 @@ static void leon_disable_irq(unsigned int irq, int cpu)
 }
 
 
+
+/**
+ * @brief force an interrupt
+ *
+ * @param irq the interrupt to force
+ * @param cpu the cpu on which to force the interrupt (set < 0 for all)
+ *
+ * @note interrupts must be enabled for this to work
+ */
+
+void leon_force_irq(unsigned int irq, int cpu)
+{
+#ifdef CONFIG_LEON3
+	if (cpu >= 0) {
+		iowrite32be((1 << irq), &leon_irqctrl_regs->irq_mpforce[cpu]);
+		return;
+	}
+#endif
+	iowrite32be((1 << irq), &leon_irqctrl_regs->irq_force);
+}
+
+
 /**
  * @brief queue a handler for delayed exectuion
  *
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 128d22c05933abb646cbc34924a659b432621603..0f9c0d81de692585af390bc04923b1593de26847 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -21,6 +21,10 @@
 #include <stack.h>
 #include <kernel/kmem.h>
 
+#include <kernel/sched.h>
+
+#include <kernel/smp.h>
+
 void *_kernel_stack_top;
 void *_kernel_stack_bottom;
 
@@ -56,8 +60,6 @@ static void reserve_kernel_stack(void)
 	/* the (aligned) top of the stack */
 	_kernel_stack_top = (void *) (char *) _kernel_stack_bottom + k_stack_sz;
 	_kernel_stack_top = ALIGN_PTR(_kernel_stack_top, STACK_ALIGN);
-
-	printk("xxxxx reserved %p to %p\n", _kernel_stack_top, _kernel_stack_bottom);
 }
 
 
@@ -116,26 +118,30 @@ extern struct task_struct *kernel[];
 void smp_cpu_entry(void)
 {
 
-     reserve_kernel_stack();
-     BUG_ON(stack_migrate(NULL, _kernel_stack_top));
+	reserve_kernel_stack();
+	BUG_ON(stack_migrate(NULL, _kernel_stack_top));
+
+	printk("hi i'm cpu %d\n", leon3_cpuid());
 
-     printk("hi i'm cpu %d\n", leon3_cpuid());
+	BUG_ON(!leon3_cpuid());
 
-     BUG_ON(!leon3_cpuid());
-      /* signal ready */
-      iowrite32be(0x1, &cpu1_ready);
+	/* signal ready */
+	iowrite32be(0x1, &cpu1_ready);
 
 	while (ioread32be(&cpu1_ready) != 0x2);
+
 	BUG_ON(clockevents_offer_device());
+
 	kthread_init_main();
 
-      iowrite32be(0x3, &cpu1_ready);
+	iowrite32be(0x3, &cpu1_ready);
+
 	while (ioread32be(&cpu1_ready) != 0x4);
-      while(1) {
-//	     printk(".\n");
-	      cpu_relax();
-      }
-//	      printk("1\n");
+
+	sched_enable();
+
+	while(1)
+		cpu_relax();
 }
 
 
@@ -164,5 +170,9 @@ void setup_arch(void)
 
 	sparc_clockevent_init();
 
+	smp_init();
+
 	boot_cpus();
+
+	sched_enable();
 }
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
new file mode 100644
index 0000000000000000000000000000000000000000..f50a053789ef038bd04e6312f84edae2aeca03a8
--- /dev/null
+++ b/arch/sparc/kernel/smp.c
@@ -0,0 +1,47 @@
+/**
+ * @file arch/sparc/kernel/smp.c
+ *
+ * @ingroup sparc
+ * @brief implements architecture-specific @ref kernel_smp interface
+ */
+
+#include <kernel/smp.h>
+#include <irq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_LEON3
+#include <asm/leon.h>
+#endif
+
+
+int smp_cpu_id(void)
+{
+#ifdef CONFIG_LEON3
+	return leon3_cpuid();
+#else /* !CONFIG_LEON3 */
+	return 0;
+#endif /* CONFIG_LEON3 */
+}
+
+
+void smp_send_reschedule(int cpu)
+{
+#ifdef CONFIG_LEON3
+	/* trigger reschedule via forced IRQMP extended interrupt */
+	/* TODO sanity check for cpu id */
+	leon_force_irq(LEON3_IPIRQ, cpu);
+#endif /* CONFIG_LEON3 */
+}
+
+
+void smp_init(void)
+{
+#ifdef CONFIG_LEON3
+
+	/* XXX need number of CPUs here */
+	leon_enable_irq(LEON3_IPIRQ, 0);
+	leon_enable_irq(LEON3_IPIRQ, 1);
+
+#endif /* CONFIG_LEON3 */
+}