diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/aviion/aviion/av400_machdep.c | 174 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/av530_machdep.c | 159 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/cio_clock.c | 11 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/locore.S | 67 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/machdep.c | 126 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/prom.c | 25 | ||||
-rw-r--r-- | sys/arch/aviion/aviion/rtc_clock.c | 10 | ||||
-rw-r--r-- | sys/arch/aviion/conf/GENERIC.MP | 15 | ||||
-rw-r--r-- | sys/arch/aviion/dev/dart.c | 4 | ||||
-rw-r--r-- | sys/arch/aviion/dev/mainbus.c | 11 | ||||
-rw-r--r-- | sys/arch/aviion/include/av530.h | 18 | ||||
-rw-r--r-- | sys/arch/aviion/include/board.h | 8 | ||||
-rw-r--r-- | sys/arch/aviion/include/prom.h | 11 |
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); |