summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/aviion/aviion/av400_machdep.c174
-rw-r--r--sys/arch/aviion/aviion/av530_machdep.c159
-rw-r--r--sys/arch/aviion/aviion/cio_clock.c11
-rw-r--r--sys/arch/aviion/aviion/locore.S67
-rw-r--r--sys/arch/aviion/aviion/machdep.c126
-rw-r--r--sys/arch/aviion/aviion/prom.c25
-rw-r--r--sys/arch/aviion/aviion/rtc_clock.c10
-rw-r--r--sys/arch/aviion/conf/GENERIC.MP15
-rw-r--r--sys/arch/aviion/dev/dart.c4
-rw-r--r--sys/arch/aviion/dev/mainbus.c11
-rw-r--r--sys/arch/aviion/include/av530.h18
-rw-r--r--sys/arch/aviion/include/board.h8
-rw-r--r--sys/arch/aviion/include/prom.h11
13 files changed, 585 insertions, 54 deletions
diff --git a/sys/arch/aviion/aviion/av400_machdep.c b/sys/arch/aviion/aviion/av400_machdep.c
index 761c8861e0f..1bf0012b93b 100644
--- a/sys/arch/aviion/aviion/av400_machdep.c
+++ b/sys/arch/aviion/aviion/av400_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: av400_machdep.c,v 1.17 2010/04/24 18:44:25 miod Exp $ */
+/* $OpenBSD: av400_machdep.c,v 1.18 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2006, 2007, Miodrag Vallat.
*
@@ -159,7 +159,13 @@
#include <aviion/dev/sysconvar.h>
#include <aviion/dev/vmevar.h>
+#ifdef MULTIPROCESSOR0
+#include <machine/db_machdep.h>
+#endif
+
u_int av400_safe_level(u_int, u_int);
+void av400_clock_ipi_handler(struct trapframe *);
+void av400_ipi_handler(struct trapframe *);
const pmap_table_entry
av400_ptable[] = {
@@ -193,6 +199,10 @@ const struct board board_av400 = {
av400_getipl,
av400_setipl,
av400_raiseipl,
+#ifdef MULTIPROCESSOR
+ NULL, /* av400_send_ipi, */
+ m88100_smp_setup,
+#endif
av400_intsrc,
av400_get_vme_ranges,
@@ -216,11 +226,11 @@ u_int32_t av400_int_mask_reg[] = { 0, 0, 0, 0 };
u_int av400_curspl[] = { IPL_HIGH, IPL_HIGH, IPL_HIGH, IPL_HIGH };
-#ifdef MULTIPROCESSOR
+#ifdef MULTIPROCESSOR0
/*
* Interrupts allowed on secondary processors.
*/
-#define SLAVE_MASK 0 /* AV400_IRQ_SWI0 | AV400_IRQ_SWI1 */
+#define SLAVE_MASK 0
#endif
/*
@@ -288,6 +298,11 @@ av400_safe_level(u_int mask, u_int curlevel)
{
int i;
+#ifdef MULTIPROCESSOR0
+ if (mask & AV400_CLOCK_IPI_MASK)
+ curlevel = max(IPL_CLOCK, curlevel);
+ mask &= ~(AV400_IPI_MASK | AV400_CLOCK_IPI_MASK);
+#endif
for (i = curlevel; i < NIPLS; i++)
if ((int_mask_val[i] & mask) == 0)
return i;
@@ -312,9 +327,12 @@ av400_setipl(u_int level)
curspl = av400_curspl[cpu];
mask = int_mask_val[level];
-#ifdef MULTIPROCESSOR
+#ifdef MULTIPROCESSOR0
if (cpu != master_cpu)
mask &= SLAVE_MASK;
+ mask |= AV400_SWI_IPI_MASK(cpu);
+ if (level < IPL_CLOCK)
+ mask |= AV400_SWI_CLOCK_IPI_MASK(cpu);
#endif
av400_curspl[cpu] = level;
@@ -339,9 +357,12 @@ av400_raiseipl(u_int level)
curspl = av400_curspl[cpu];
if (curspl < level) {
mask = int_mask_val[level];
-#ifdef MULTIPROCESSOR
+#ifdef MULTIPROCESSOR0
if (cpu != master_cpu)
mask &= SLAVE_MASK;
+ mask |= AV400_SWI_IPI_MASK(cpu);
+ if (level < IPL_CLOCK)
+ mask |= AV400_SWI_CLOCK_IPI_MASK(cpu);
#endif
av400_curspl[cpu] = level;
@@ -356,6 +377,89 @@ av400_raiseipl(u_int level)
return curspl;
}
+#ifdef MULTIPROCESSOR0
+
+void
+av400_send_ipi(int ipi, cpuid_t cpu)
+{
+ struct cpu_info *ci = &m88k_cpus[cpu];
+ uint32_t bits = 0;
+
+ if (ci->ci_ipi & ipi)
+ return;
+
+ atomic_setbits_int(&ci->ci_ipi, ipi);
+ if (ipi & ~(CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
+ bits |= AV400_SWI_IPI_BIT(cpu);
+ if (ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
+ bits |= AV400_SWI_CLOCK_IPI_BIT(cpu);
+ *(volatile u_int32_t *)AV400_SETSWI = bits;
+}
+
+/*
+ * Process inter-processor interrupts.
+ */
+
+/*
+ * Unmaskable IPIs - those are processed with interrupts disabled,
+ * and no lock held.
+ */
+void
+av400_ipi_handler(struct trapframe *eframe)
+{
+ struct cpu_info *ci = curcpu();
+ int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);
+
+ *(volatile u_int32_t *)AV400_CLRSWI = AV400_SWI_IPI_BIT(ci->ci_cpuid);
+ atomic_clearbits_int(&ci->ci_ipi, ipi);
+
+ if (ipi & CI_IPI_DDB) {
+#ifdef DDB
+ /*
+ * Another processor has entered DDB. Spin on the ddb lock
+ * until it is done.
+ */
+ extern struct __mp_lock ddb_mp_lock;
+
+ __mp_lock(&ddb_mp_lock);
+ __mp_unlock(&ddb_mp_lock);
+
+ /*
+ * If ddb is hoping to us, it's our turn to enter ddb now.
+ */
+ if (ci->ci_cpuid == ddb_mp_nextcpu)
+ Debugger();
+#endif
+ }
+ if (ipi & CI_IPI_NOTIFY) {
+ /* nothing to do */
+ }
+}
+
+/*
+ * Maskable IPIs
+ */
+void
+av400_clock_ipi_handler(struct trapframe *eframe)
+{
+ struct cpu_info *ci = curcpu();
+ int ipi = ci->ci_ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK);
+
+ /* clear clock ipi interrupt */
+ *(volatile u_int32_t *)AV400_CLRSWI =
+ AV400_SWI_CLOCK_IPI_BIT(ci->ci_cpuid);
+ atomic_clearbits_int(&ci->ci_ipi, ipi);
+
+ if (ipi & CI_IPI_HARDCLOCK)
+ hardclock((struct clockframe *)eframe);
+#if 0 /* no separate statclock yet */
+ if (ipi & CI_IPI_STATCLOCK)
+ statclock((struct clockframe *)eframe);
+#endif
+}
+
+#endif
+
/*
* Provide the interrupt masks for a given logical interrupt source.
*/
@@ -437,7 +541,7 @@ static const u_int av400_obio_vec[32] = {
void
av400_intr(struct trapframe *eframe)
{
- int cpu = cpu_number();
+ u_int cpu = cpu_number();
u_int32_t cur_mask, ign_mask;
u_int level, old_spl;
struct intrhand *intr;
@@ -460,19 +564,56 @@ av400_intr(struct trapframe *eframe)
* Spurious interrupts - may be caused by debug output clearing
* DUART interrupts.
*/
+#ifdef MULTIPROCESSOR0
+ if (cpu != master_cpu) {
+ if (++problems >= 10) {
+ printf("cpu%d: interrupt pin won't clear, "
+ "disabling processor\n", cpu);
+ cpu_emergency_disable();
+ /* NOTREACHED */
+ }
+ }
+#endif
flush_pipeline();
goto out;
}
uvmexp.intrs++;
+#ifdef MULTIPROCESSOR0
+ /*
+ * Handle unmaskable IPIs immediately, so that we can reenable
+ * interrupts before further processing. We rely on the interrupt
+ * mask to make sure that if we get an IPI, it's really for us
+ * and no other processor.
+ */
+ if (cur_mask & AV400_IPI_MASK) {
+ av400_ipi_handler(eframe);
+ cur_mask &= ~AV400_IPI_MASK;
+ if (cur_mask == 0)
+ goto out;
+ }
+#endif
+
+#ifdef MULTIPROCESSOR
+ if (old_spl < IPL_SCHED)
+ __mp_lock(&kernel_lock);
+#endif
+
/*
* We want to service all interrupts marked in the IST register
* They are all valid because the mask would have prevented them
* from being generated otherwise. We will service them in order of
* priority.
*/
- do {
+ for (;;) {
+ cur_mask = ISR_GET_CURRENT_MASK(cpu);
+#ifdef MULTIPROCESSOR0
+ cur_mask &= ~AV400_IPI_MASK;
+#endif
+ if ((cur_mask & ~ign_mask) == 0)
+ break;
+
level = av400_safe_level(cur_mask, old_spl);
av400_setipl(level);
@@ -481,6 +622,18 @@ av400_intr(struct trapframe *eframe)
unmasked = 1;
}
+#ifdef MULTIPROCESSOR0
+ /*
+ * Handle pending maskable IPIs first.
+ */
+ if (cur_mask & AV400_CLOCK_IPI_MASK) {
+ av400_clock_ipi_handler(eframe);
+ cur_mask &= ~AV400_CLOCK_IPI_MASK;
+ if ((cur_mask & ~ign_mask) == 0)
+ break;
+ }
+#endif
+
/* find the first bit set in the current mask */
warn = 0;
intbit = ff1(cur_mask);
@@ -550,7 +703,7 @@ av400_intr(struct trapframe *eframe)
warn == 1 ? "spurious" : "unclaimed",
level, intbit, cur_mask, AV400_IST_STRING);
}
- } while (((cur_mask = ISR_GET_CURRENT_MASK(cpu)) & ~ign_mask) != 0);
+ }
#ifdef DIAGNOSTIC
if (ign_mask != 0) {
@@ -560,6 +713,11 @@ av400_intr(struct trapframe *eframe)
problems = 0;
#endif
+#ifdef MULTIPROCESSOR
+ if (old_spl < IPL_SCHED)
+ __mp_unlock(&kernel_lock);
+#endif
+
out:
/*
* process any remaining data access exceptions before
diff --git a/sys/arch/aviion/aviion/av530_machdep.c b/sys/arch/aviion/aviion/av530_machdep.c
index 1da9e0bad35..70a2dc4bee1 100644
--- a/sys/arch/aviion/aviion/av530_machdep.c
+++ b/sys/arch/aviion/aviion/av530_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: av530_machdep.c,v 1.3 2010/04/24 18:44:25 miod Exp $ */
+/* $OpenBSD: av530_machdep.c,v 1.4 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2006, 2007, 2010 Miodrag Vallat.
*
@@ -48,7 +48,13 @@
#include <aviion/dev/sysconvar.h>
#include <aviion/dev/vmevar.h>
+#ifdef MULTIPROCESSOR
+#include <machine/db_machdep.h>
+#endif
+
u_int av530_safe_level(u_int, u_int, u_int);
+void av530_clock_ipi_handler(struct trapframe *);
+void av530_ipi_handler(struct trapframe *);
const pmap_table_entry av530_ptable[] = {
{ AV530_PROM, AV530_PROM, AV530_PROM_SIZE,
@@ -81,6 +87,10 @@ const struct board board_av530 = {
av530_getipl,
av530_setipl,
av530_raiseipl,
+#ifdef MULTIPROCESSOR
+ av530_send_ipi,
+ m88100_smp_setup,
+#endif
av530_intsrc,
av530_get_vme_ranges,
@@ -107,7 +117,7 @@ u_int av530_curspl[] = { IPL_HIGH, IPL_HIGH, IPL_HIGH, IPL_HIGH };
/*
* Interrupts allowed on secondary processors.
*/
-#define SLAVE_MASK 0 /* AV530_IRQ_SWI0 | AV530_IRQ_SWI1 */
+#define SLAVE_MASK 0
#define SLAVE_EXMASK 0
#endif
@@ -200,6 +210,11 @@ av530_safe_level(u_int mask, u_int exmask, u_int curlevel)
{
int i;
+#ifdef MULTIPROCESSOR
+ if (mask & AV530_CLOCK_IPI_MASK)
+ curlevel = max(IPL_CLOCK, curlevel);
+ mask &= ~(AV530_IPI_MASK | AV530_CLOCK_IPI_MASK);
+#endif
for (i = curlevel; i < NIPLS; i++)
if ((int_mask_val[i] & mask) == 0 &&
(ext_int_mask_val[i] & exmask) == 0)
@@ -231,6 +246,9 @@ av530_setipl(u_int level)
mask &= SLAVE_MASK;
exmask &= SLAVE_EXMASK;
}
+ mask |= AV530_SWI_IPI_MASK(cpu);
+ if (level < IPL_CLOCK)
+ mask |= AV530_SWI_CLOCK_IPI_MASK(cpu);
#endif
av530_curspl[cpu] = level;
@@ -262,6 +280,9 @@ av530_raiseipl(u_int level)
mask &= SLAVE_MASK;
exmask &= SLAVE_EXMASK;
}
+ mask |= AV530_SWI_IPI_MASK(cpu);
+ if (level < IPL_CLOCK)
+ mask |= AV530_SWI_CLOCK_IPI_MASK(cpu);
#endif
av530_curspl[cpu] = level;
@@ -278,6 +299,89 @@ av530_raiseipl(u_int level)
return curspl;
}
+#ifdef MULTIPROCESSOR
+
+void
+av530_send_ipi(int ipi, cpuid_t cpu)
+{
+ struct cpu_info *ci = &m88k_cpus[cpu];
+ uint32_t bits = 0;
+
+ if (ci->ci_ipi & ipi)
+ return;
+
+ atomic_setbits_int(&ci->ci_ipi, ipi);
+ if (ipi & ~(CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
+ bits |= AV530_SWI_IPI_BIT(cpu);
+ if (ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
+ bits |= AV530_SWI_CLOCK_IPI_BIT(cpu);
+ *(volatile u_int32_t *)AV530_SETSWI = bits;
+}
+
+/*
+ * Process inter-processor interrupts.
+ */
+
+/*
+ * Unmaskable IPIs - those are processed with interrupts disabled,
+ * and no lock held.
+ */
+void
+av530_ipi_handler(struct trapframe *eframe)
+{
+ struct cpu_info *ci = curcpu();
+ int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);
+
+ *(volatile u_int32_t *)AV530_CLRSWI = AV530_SWI_IPI_BIT(ci->ci_cpuid);
+ atomic_clearbits_int(&ci->ci_ipi, ipi);
+
+ if (ipi & CI_IPI_DDB) {
+#ifdef DDB
+ /*
+ * Another processor has entered DDB. Spin on the ddb lock
+ * until it is done.
+ */
+ extern struct __mp_lock ddb_mp_lock;
+
+ __mp_lock(&ddb_mp_lock);
+ __mp_unlock(&ddb_mp_lock);
+
+ /*
+ * If ddb is hoping to us, it's our turn to enter ddb now.
+ */
+ if (ci->ci_cpuid == ddb_mp_nextcpu)
+ Debugger();
+#endif
+ }
+ if (ipi & CI_IPI_NOTIFY) {
+ /* nothing to do */
+ }
+}
+
+/*
+ * Maskable IPIs
+ */
+void
+av530_clock_ipi_handler(struct trapframe *eframe)
+{
+ struct cpu_info *ci = curcpu();
+ int ipi = ci->ci_ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK);
+
+ /* clear clock ipi interrupt */
+ *(volatile u_int32_t *)AV530_CLRSWI =
+ AV530_SWI_CLOCK_IPI_BIT(ci->ci_cpuid);
+ atomic_clearbits_int(&ci->ci_ipi, ipi);
+
+ if (ipi & CI_IPI_HARDCLOCK)
+ hardclock((struct clockframe *)eframe);
+#if 0 /* no separate statclock yet */
+ if (ipi & CI_IPI_STATCLOCK)
+ statclock((struct clockframe *)eframe);
+#endif
+}
+
+#endif
+
/*
* Provide the interrupt masks for a given logical interrupt source.
*/
@@ -443,12 +547,42 @@ av530_intr(struct trapframe *eframe)
* Spurious interrupts - may be caused by debug output clearing
* DUART interrupts.
*/
+#ifdef MULTIPROCESSOR
+ if (cpu != master_cpu) {
+ if (++problems >= 10) {
+ printf("cpu%d: interrupt pin won't clear, "
+ "disabling processor\n", cpu);
+ cpu_emergency_disable();
+ /* NOTREACHED */
+ }
+ }
+#endif
flush_pipeline();
goto out;
}
uvmexp.intrs++;
+#ifdef MULTIPROCESSOR
+ /*
+ * Handle unmaskable IPIs immediately, so that we can reenable
+ * interrupts before further processing. We rely on the interrupt
+ * mask to make sure that if we get an IPI, it's really for us
+ * and no other processor.
+ */
+ if (cur_mask & AV530_IPI_MASK) {
+ av530_ipi_handler(eframe);
+ cur_mask &= ~AV530_IPI_MASK;
+ if (cur_mask == 0 && cur_exmask == 0)
+ goto out;
+ }
+#endif
+
+#ifdef MULTIPROCESSOR
+ if (old_spl < IPL_SCHED)
+ __mp_lock(&kernel_lock);
+#endif
+
/*
* We want to service all interrupts marked in the IST register
* They are all valid because the mask would have prevented them
@@ -457,6 +591,9 @@ av530_intr(struct trapframe *eframe)
*/
for (;;) {
cur_mask = ISR_GET_CURRENT_MASK(cpu);
+#ifdef MULTIPROCESSOR
+ cur_mask &= ~AV530_IPI_MASK;
+#endif
cur_exmask = EXISR_GET_CURRENT_MASK(cpu);
if ((cur_mask & ~ign_mask) == 0 &&
(cur_exmask & ~ign_exmask) == 0)
@@ -470,6 +607,19 @@ av530_intr(struct trapframe *eframe)
unmasked = 1;
}
+#ifdef MULTIPROCESSOR
+ /*
+ * Handle pending maskable IPIs first.
+ */
+ if (cur_mask & AV530_CLOCK_IPI_MASK) {
+ av530_clock_ipi_handler(eframe);
+ cur_mask &= ~AV530_CLOCK_IPI_MASK;
+ if ((cur_mask & ~ign_mask) == 0 &&
+ (cur_exmask & ~ign_exmask) == 0)
+ break;
+ }
+#endif
+
/* find the first bit set in the current mask */
warn = 0;
if (cur_mask != 0) {
@@ -575,6 +725,11 @@ av530_intr(struct trapframe *eframe)
problems = 0;
#endif
+#ifdef MULTIPROCESSOR
+ if (old_spl < IPL_SCHED)
+ __mp_unlock(&kernel_lock);
+#endif
+
out:
/*
* process any remaining data access exceptions before
diff --git a/sys/arch/aviion/aviion/cio_clock.c b/sys/arch/aviion/aviion/cio_clock.c
index 7d405cefdc6..25a9aa720dc 100644
--- a/sys/arch/aviion/aviion/cio_clock.c
+++ b/sys/arch/aviion/aviion/cio_clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cio_clock.c,v 1.2 2010/04/21 19:33:45 miod Exp $ */
+/* $OpenBSD: cio_clock.c,v 1.3 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2006, 2007, 2009 Miodrag Vallat.
*
@@ -143,6 +143,7 @@
#include <uvm/uvm_extern.h>
+#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/avcommon.h>
@@ -272,6 +273,14 @@ cio_clockintr(void *eframe)
hardclock(eframe);
+#ifdef MULTIPROCESSOR
+ /*
+ * Send an IPI to all other processors, so they can get their
+ * own ticks.
+ */
+ m88k_broadcast_ipi(CI_IPI_HARDCLOCK);
+#endif
+
return (1);
}
diff --git a/sys/arch/aviion/aviion/locore.S b/sys/arch/aviion/aviion/locore.S
index 21d3be97b7c..0bb7e917820 100644
--- a/sys/arch/aviion/aviion/locore.S
+++ b/sys/arch/aviion/aviion/locore.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.S,v 1.12 2010/04/18 15:04:51 miod Exp $ */
+/* $OpenBSD: locore.S,v 1.13 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2005, Miodrag Vallat.
* Copyright (c) 1998 Steve Murphree, Jr.
@@ -205,6 +205,35 @@ ASLOCAL(main_panic)
* to the comments there for details.
*/
GLOBAL(secondary_start)
+ /*
+ * We have been started early, but there is nothing we can do yet.
+ * We'll just spin until we can get the hatching mutex.
+ */
+ or.u r11, r0, hi16(_C_LABEL(cpu_hatch_mutex))
+ or r11, r11, lo16(_C_LABEL(cpu_hatch_mutex))
+1:
+ or r22, r0, 1
+ xmem r22, r11, r0 /* if r22 becomes zero, we own the lock... */
+ bcnd eq0, r22, 4f /* ... but if not, we must wait */
+2:
+ /* just watch the lock until it looks clear */
+ ld r22, r11, r0
+ bcnd eq0, r22, 1b
+ /* wait a bit to avoid overloading the bus */
+ or.u r2, r0, 1
+3:
+ subu r2, r2, 1
+ bcnd ne0, r2, 3b
+ br 2b
+4:
+
+ /*
+ * We are now running free with cpu_hatch_mutex held; other
+ * secondary processors are waiting for the lock, and the main
+ * processor is waiting for us to decrease the hatch counter,
+ * which we'll do in secondary_main() later.
+ */
+
or.u r31, r0, hi16(_ASM_LABEL(slavestack_end))
or r31, r31, lo16(_ASM_LABEL(slavestack_end))
@@ -224,29 +253,6 @@ GLOBAL(secondary_start)
stcr r11, CPU
/*
- * Since there may be more than one secondary MPU, compete with them
- * to initialize safely.
- */
- or.u r11, r0, hi16(_C_LABEL(cpu_mutex))
- or r11, r11, lo16(_C_LABEL(cpu_mutex))
-1:
- or r22, r0, 1
- xmem r22, r11, r0 /* If r22 gets 0, we have the lock... */
- bcnd eq0, r22, 4f /* ...but if not, we must wait */
-2:
- /* just watch the lock until it looks clear */
- ld r22, r11, r0
- bcnd eq0, r22, 1b
- /* since we can be here with caches off, add a few nops to
- keep the bus from getting overloaded */
- or r2, r0, lo16(1000)
-3:
- subu r2, r2, 1
- bcnd ne0, r2, 3b
- br 1b
-4:
-
- /*
* While holding the cpu_mutex, the secondary cpu can use the slavestack
* to call secondary_pre_main() to determine its cpu number.
* After that, however, it should allocate its own stack and switch
@@ -261,6 +267,14 @@ GLOBAL(secondary_start)
bsr.n _C_LABEL(secondary_main)
addu r31, r2, USPACE /* switch to startup stack */
+ /*
+ * Dummy mp_atomic_begin() and mp_atomic_end() routine, so that
+ * we can interact with ddb if things go wrong very early during
+ * bootstrap. Of course this should never happen (-:
+ */
+ASLOCAL(dummy_mplock)
+ jmp r1
+
#endif /* MULTIPROCESSOR */
/*
@@ -317,7 +331,12 @@ ASLOCAL(dummy_cpu)
word 3 /* CIF_PRIMARY | CIF_ALIVE */ /* ci_alive */
word 0 /* ci_curproc */
word 0 /* ci_curpcb */
+ word 0 /* ci_curpmap */
word 0 /* ci_cpuid */
+ word _ASM_LABEL(dummy_mplock) /* ci_mp_atomic_begin */
+ word _ASM_LABEL(dummy_mplock) /* ci_mp_atomic_end */
+
+ space CPU_INFO_SIZEOF - 7 * 4
#endif /* MULTIPROCESSOR */
#if defined(DDB) || NKSYMS > 0
diff --git a/sys/arch/aviion/aviion/machdep.c b/sys/arch/aviion/aviion/machdep.c
index aa28b7f6848..4d58c533bb5 100644
--- a/sys/arch/aviion/aviion/machdep.c
+++ b/sys/arch/aviion/aviion/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.36 2010/04/24 18:44:25 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.37 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2007 Miodrag Vallat.
*
@@ -114,6 +114,8 @@
void aviion_bootstrap(void);
void aviion_identify(void);
void consinit(void);
+void cpu_hatch_secondary_processors(void);
+void cpu_setup_secondary_processors(void);
__dead void doboot(void);
void dumpconf(void);
void dumpsys(void);
@@ -127,7 +129,9 @@ struct vm_map *exec_map = NULL;
struct vm_map *phys_map = NULL;
#ifdef MULTIPROCESSOR
-__cpu_simple_lock_t cpu_mutex = __SIMPLELOCK_UNLOCKED;
+u_int hatch_pending_count = 0;
+__cpu_simple_lock_t cpu_hatch_mutex = __SIMPLELOCK_LOCKED;
+__cpu_simple_lock_t cpu_boot_mutex = __SIMPLELOCK_LOCKED;
#endif
/*
@@ -535,10 +539,12 @@ vaddr_t
secondary_pre_main()
{
struct cpu_info *ci;
+ vaddr_t init_stack;
set_cpu_number(cmmu_cpu_number()); /* Determine cpu number by CMMU */
ci = curcpu();
ci->ci_curproc = &proc0;
+ platform->smp_setup(ci);
splhigh();
@@ -554,6 +560,11 @@ secondary_pre_main()
if (init_stack == (vaddr_t)NULL) {
printf("cpu%d: unable to allocate startup stack\n",
ci->ci_cpuid);
+ /*
+ * Release cpu_hatch_mutex to let other secondary processors
+ * have a chance to run.
+ */
+ __cpu_simple_unlock(&cpu_hatch_mutex);
for (;;) ;
}
@@ -573,17 +584,28 @@ secondary_main()
int s;
cpu_configuration_print(0);
- sched_init_cpu(ci);
ncpus++;
- __cpu_simple_unlock(&cpu_mutex);
+ sched_init_cpu(ci);
microuptime(&ci->ci_schedstate.spc_runtime);
ci->ci_curproc = NULL;
+ ci->ci_randseed = random();
+ SET(ci->ci_flags, CIF_ALIVE);
- set_psr(get_psr() & ~PSR_IND);
- spl0();
+ /*
+ * Release cpu_hatch_mutex to let other secondary processors
+ * have a chance to run.
+ */
+ hatch_pending_count--;
+ __cpu_simple_unlock(&cpu_hatch_mutex);
+
+ /* wait for cpu_boot_secondary_processors() */
+ __cpu_simple_lock(&cpu_boot_mutex);
+ __cpu_simple_unlock(&cpu_boot_mutex);
+ spl0();
SCHED_LOCK(s);
+ set_psr(get_psr() & ~PSR_IND);
cpu_switchto(NULL, sched_chooseproc());
}
@@ -708,6 +730,9 @@ aviion_bootstrap()
setup_board_config();
master_cpu = cmmu_init();
set_cpu_number(master_cpu);
+#ifdef MULTIPROCESSOR
+ platform->smp_setup(curcpu());
+#endif
SET(curcpu()->ci_flags, CIF_ALIVE | CIF_PRIMARY);
#ifdef M88100
@@ -716,6 +741,14 @@ aviion_bootstrap()
}
#endif
+#ifdef MULTIPROCESSOR
+ /*
+ * We need to start secondary processors while it is still
+ * possible to invoke SCM functions.
+ */
+ cpu_hatch_secondary_processors();
+#endif
+
/*
* Now that set_cpu_number() set us with a valid cpu_info pointer,
* we need to initialize p_addr and curpcb before autoconf, for the
@@ -748,21 +781,64 @@ aviion_bootstrap()
}
#ifdef MULTIPROCESSOR
+/*
+ * Spin processors while we can use the PROM, and have them wait for
+ * cpu_hatch_mutex.
+ */
void
-cpu_boot_secondary_processors()
+cpu_hatch_secondary_processors()
{
+ struct cpu_info *ci = curcpu();
cpuid_t cpu;
int rc;
extern void secondary_start(void);
+ /* we might not have a working SMP implementation on this system. */
+ if (platform->send_ipi == NULL)
+ return;
+
for (cpu = 0; cpu < ncpusfound; cpu++) {
- if (cpu != curcpu()->ci_cpuid) {
- rc = scm_spincpu(cpu, (vaddr_t)secondary_start);
- if (rc != 0)
- printf("cpu%d: spin_cpu error %d\n", cpu, rc);
+ if (cpu != ci->ci_cpuid) {
+ rc = scm_jpstart(cpu, (vaddr_t)secondary_start);
+ switch (rc) {
+ case JPSTART_OK:
+ hatch_pending_count++;
+ break;
+ case JPSTART_NO_JP:
+ break;
+ case JPSTART_SINGLE_JP:
+ /* this should never happen, but just in case */
+ ncpusfound = 1;
+ return;
+ default:
+ printf("CPU%d failed to start, error %d\n",
+ cpu, rc);
+ break;
+ }
}
}
}
+
+/*
+ * Release cpu_hatch_mutex to let secondary processors initialize.
+ */
+void
+cpu_setup_secondary_processors()
+{
+ __cpu_simple_unlock(&cpu_hatch_mutex);
+ while (hatch_pending_count != 0)
+ delay(100000);
+}
+
+/*
+ * Release cpu_boot_mutex to let secondary processors start running
+ * processes.
+ */
+void
+cpu_boot_secondary_processors()
+{
+ __cpu_simple_unlock(&cpu_boot_mutex);
+}
#endif
/*
@@ -820,6 +896,34 @@ raiseipl(int level)
return (int)platform->raiseipl((u_int)level);
}
+#ifdef MULTIPROCESSOR
+void
+m88k_send_ipi(int ipi, cpuid_t cpu)
+{
+ struct cpu_info *ci;
+
+ ci = &m88k_cpus[cpu];
+ if (ISSET(ci->ci_flags, CIF_ALIVE))
+ platform->send_ipi(ipi, cpu);
+}
+
+void
+m88k_broadcast_ipi(int ipi)
+{
+ struct cpu_info *us = curcpu();
+ struct cpu_info *ci;
+ CPU_INFO_ITERATOR cii;
+
+ CPU_INFO_FOREACH(cii, ci) {
+ if (ci == us)
+ continue;
+
+ if (ISSET(ci->ci_flags, CIF_ALIVE))
+ platform->send_ipi(ipi, ci->ci_cpuid);
+ }
+}
+#endif
+
void
intsrc_enable(u_int intsrc, int ipl)
{
diff --git a/sys/arch/aviion/aviion/prom.c b/sys/arch/aviion/aviion/prom.c
index 29d0390b013..2a3f1707dc2 100644
--- a/sys/arch/aviion/aviion/prom.c
+++ b/sys/arch/aviion/aviion/prom.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: prom.c,v 1.3 2007/12/20 21:19:32 miod Exp $ */
+/* $OpenBSD: prom.c,v 1.4 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2006, Miodrag Vallat.
@@ -286,3 +286,26 @@ scm_sysid()
return (ret);
}
+
+#ifdef MULTIPROCESSOR
+u_int
+scm_jpstart(cpuid_t cpu, vaddr_t addr)
+{
+ SCM_DECL;
+ u_int ret;
+
+ psr = get_psr();
+ set_psr(psr | PSR_IND);
+ SCM_CONTEXT();
+ SCM_VBR();
+ __asm__ __volatile__ ("or r2, r0, %0; or r3, r0, %1" : :
+ "r" (cpu), "r" (addr));
+ SCM_CALL(SCM_JPSTART);
+ __asm__ __volatile__ ("or %0, r0, r2" : "=r" (ret));
+ OS_CONTEXT();
+ OS_VBR();
+ set_psr(psr);
+
+ return (ret);
+}
+#endif
diff --git a/sys/arch/aviion/aviion/rtc_clock.c b/sys/arch/aviion/aviion/rtc_clock.c
index 696ad7861a4..dc153a6a842 100644
--- a/sys/arch/aviion/aviion/rtc_clock.c
+++ b/sys/arch/aviion/aviion/rtc_clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtc_clock.c,v 1.1 2010/04/21 19:33:45 miod Exp $ */
+/* $OpenBSD: rtc_clock.c,v 1.2 2010/04/24 18:46:51 miod Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -113,6 +113,14 @@ rtc_clockintr(void *frame)
*(volatile uint32_t *)AV530_PIT0_CS = AV530_PIT_CTEN;
hardclock(frame);
+#ifdef MULTIPROCESSOR
+ /*
+ * Send an IPI to all other processors, so they can get their
+ * own ticks.
+ */
+ m88k_broadcast_ipi(CI_IPI_HARDCLOCK);
+#endif
+
return 1;
}
diff --git a/sys/arch/aviion/conf/GENERIC.MP b/sys/arch/aviion/conf/GENERIC.MP
new file mode 100644
index 00000000000..fcbddc61acf
--- /dev/null
+++ b/sys/arch/aviion/conf/GENERIC.MP
@@ -0,0 +1,15 @@
+# $OpenBSD: GENERIC.MP,v 1.1 2010/04/24 18:46:53 miod Exp $
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+include "arch/aviion/conf/GENERIC"
+
+option MULTIPROCESSOR
+#option MP_LOCKDEBUG
diff --git a/sys/arch/aviion/dev/dart.c b/sys/arch/aviion/dev/dart.c
index abbe4d799b3..fe83d35661e 100644
--- a/sys/arch/aviion/dev/dart.c
+++ b/sys/arch/aviion/dev/dart.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dart.c,v 1.8 2010/04/12 12:57:51 tedu Exp $ */
+/* $OpenBSD: dart.c,v 1.9 2010/04/24 18:46:55 miod Exp $ */
/*
* Mach Operating System
@@ -812,7 +812,7 @@ dartintr(void *arg)
* ready change on a disabled port). This should not happen,
* but we have to claim the interrupt anyway.
*/
-#ifdef DIAGNOSTIC
+#if defined(DIAGNOSTIC) && !defined(MULTIPROCESSOR)
printf("%s: spurious interrupt, isr %x imr %x\n",
sc->sc_dev.dv_xname, isr, imr);
#endif
diff --git a/sys/arch/aviion/dev/mainbus.c b/sys/arch/aviion/dev/mainbus.c
index 18ae8edb097..0c8047ce701 100644
--- a/sys/arch/aviion/dev/mainbus.c
+++ b/sys/arch/aviion/dev/mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mainbus.c,v 1.5 2010/04/24 18:44:27 miod Exp $ */
+/* $OpenBSD: mainbus.c,v 1.6 2010/04/24 18:46:55 miod Exp $ */
/*
* Copyright (c) 1998 Steve Murphree, Jr.
* Copyright (c) 2004, Miodrag Vallat.
@@ -128,6 +128,7 @@ mainbus_match(struct device *parent, void *cf, void *args)
void
mainbus_attach(struct device *parent, struct device *self, void *args)
{
+ extern void cpu_setup_secondary_processors(void);
extern char cpu_model[];
printf(": %s, cpuid 0x%04x", cpu_model, cpuid);
@@ -138,6 +139,14 @@ mainbus_attach(struct device *parent, struct device *self, void *args)
*/
cpu_configuration_print(1);
+#ifdef MULTIPROCESSOR
+ /*
+ * Let secondary processor initialize further and print their
+ * configuration information now.
+ */
+ cpu_setup_secondary_processors();
+#endif
+
(void)config_search(mainbus_scan, self, args);
}
diff --git a/sys/arch/aviion/include/av530.h b/sys/arch/aviion/include/av530.h
index 73965e000b9..62f4b907b8e 100644
--- a/sys/arch/aviion/include/av530.h
+++ b/sys/arch/aviion/include/av530.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: av530.h,v 1.2 2010/04/21 19:33:47 miod Exp $ */
+/* $OpenBSD: av530.h,v 1.3 2010/04/24 18:46:55 miod Exp $ */
/*
* Copyright (c) 2006, 2010 Miodrag Vallat
*
@@ -106,6 +106,22 @@
"\10SIGLPI\7IRQ2\5IRQ1\4SWI3\3SWI2\2SWI1\1SWI0"
/*
+ * Software interrupts 0 to 3, and 4 to 7, are used to deliver IPIs to
+ * CPU0-3. We use two software interrupts per CPU because we want clock
+ * IPIs to be maskable.
+ */
+#define AV530_CLOCK_IPI_MASK (AV530_IRQ_SWI7 | AV530_IRQ_SWI6 | \
+ AV530_IRQ_SWI5 | AV530_IRQ_SWI4)
+#define AV530_IPI_MASK (AV530_IRQ_SWI3 | AV530_IRQ_SWI2 | \
+ AV530_IRQ_SWI1 | AV530_IRQ_SWI0)
+/* values for SETSWI and CLRSWI registers */
+#define AV530_SWI_IPI_BIT(cpu) (0x01 << (cpu))
+#define AV530_SWI_CLOCK_IPI_BIT(cpu) (0x10 << (cpu))
+/* values for IEN and IST registers */
+#define AV530_SWI_IPI_MASK(cpu) (AV530_IRQ_SWI0 << (cpu))
+#define AV530_SWI_CLOCK_IPI_MASK(cpu) (AV530_IRQ_SWI4 << (cpu))
+
+/*
* Extended interrupts
*/
diff --git a/sys/arch/aviion/include/board.h b/sys/arch/aviion/include/board.h
index b4c6384b873..8424da73872 100644
--- a/sys/arch/aviion/include/board.h
+++ b/sys/arch/aviion/include/board.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: board.h,v 1.7 2010/04/24 18:44:27 miod Exp $ */
+/* $OpenBSD: board.h,v 1.8 2010/04/24 18:46:55 miod Exp $ */
/*
* Copyright (c) 2006, 2007, Miodrag Vallat
*
@@ -84,6 +84,10 @@ struct board {
u_int (*getipl)(void);
u_int (*setipl)(u_int);
u_int (*raiseipl)(u_int);
+#ifdef MULTIPROCESSOR
+ void (*send_ipi)(int, cpuid_t);
+ void (*smp_setup)(struct cpu_info *);
+#endif
u_int64_t (*intsrc)(int);
const struct vme_range *(*get_vme_ranges)(void);
@@ -103,6 +107,8 @@ void av##b##_init_clocks(void); \
u_int av##b##_getipl(void); \
u_int av##b##_setipl(u_int); \
u_int av##b##_raiseipl(u_int); \
+void av##b##_send_ipi(int, cpuid_t); \
+void av##b##_smp_setup(struct cpu_info *); \
u_int64_t av##b##_intsrc(int); \
const struct vme_range *av##b##_get_vme_ranges(void);
diff --git a/sys/arch/aviion/include/prom.h b/sys/arch/aviion/include/prom.h
index 4ce7f0f6574..1783cb20ee2 100644
--- a/sys/arch/aviion/include/prom.h
+++ b/sys/arch/aviion/include/prom.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: prom.h,v 1.2 2006/05/20 11:57:04 miod Exp $ */
+/* $OpenBSD: prom.h,v 1.3 2010/04/24 18:46:55 miod Exp $ */
/*
* Copyright (c) 2006, Miodrag Vallat.
*
@@ -39,6 +39,7 @@
#define SCM_OCRLF 0x26
#define SCM_HALT 0x63
#define SCM_STDIO 0x70
+#define SCM_JPSTART 0x100
#define SCM_REBOOT 0x101
#define SCM_CPUID 0x102
#define SCM_MSIZE 0x103
@@ -51,6 +52,13 @@
#define SCM_SYSID 0x31
#define SCM_CPUCONFIG 0x107
+/* SCM_JPSTART return values */
+#define JPSTART_OK 0
+#define JPSTART_NO_JP 1
+#define JPSTART_SINGLE_JP 2
+#define JPSTART_NOT_IDLE 3
+#define JPSTART_NO_ANSWER 4
+
struct scm_cpuconfig {
u_int32_t version;
#define SCM_CPUCONFIG_VERSION 0
@@ -65,6 +73,7 @@ u_int scm_cpuid(void);
int scm_getc(void);
void scm_getenaddr(u_char *);
__dead void scm_halt(void);
+u_int scm_jpstart(cpuid_t, vaddr_t);
u_int scm_memsize(int);
void scm_printf(const char *);
u_int scm_promver(void);