diff --git a/sys/arch/arm/arm/arm_machdep.c b/sys/arch/arm/arm/arm_machdep.c index ff7ed380090d..28b96f4ee03f 100644 --- a/sys/arch/arm/arm/arm_machdep.c +++ b/sys/arch/arm/arm/arm_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $ */ +/* $NetBSD: arm_machdep.c,v 1.14 2007/03/09 19:21:57 thorpej Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -73,10 +73,11 @@ #include "opt_compat_netbsd.h" #include "opt_execfmt.h" +#include "opt_arm_debug.h" #include -__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.14 2007/03/09 19:21:57 thorpej Exp $"); #include #include @@ -84,6 +85,7 @@ __KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $"); #include #include #include +#include #include @@ -102,6 +104,24 @@ __KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $"); */ vaddr_t vector_page; +#if defined(ARM_LOCK_CAS_DEBUG) +/* + * Event counters for tracking activity of the RAS-based _lock_cas() + * routine. + */ +struct evcnt _lock_cas_restart = + EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "restart"); +EVCNT_ATTACH_STATIC(_lock_cas_restart); + +struct evcnt _lock_cas_success = + EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "success"); +EVCNT_ATTACH_STATIC(_lock_cas_success); + +struct evcnt _lock_cas_fail = + EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "fail"); +EVCNT_ATTACH_STATIC(_lock_cas_fail); +#endif /* ARM_LOCK_CAS_DEBUG */ + /* * Clear registers on exec */ diff --git a/sys/arch/arm/arm32/genassym.cf b/sys/arch/arm/arm32/genassym.cf index 8d3faeb9e399..8ea4ed84d364 100644 --- a/sys/arch/arm/arm32/genassym.cf +++ b/sys/arch/arm/arm32/genassym.cf @@ -1,4 +1,4 @@ -# $NetBSD: genassym.cf,v 1.31 2007/02/20 00:05:14 matt Exp $ +# $NetBSD: genassym.cf,v 1.32 2007/03/09 19:21:57 thorpej Exp $ # Copyright (c) 1982, 1990 The Regents of the University of California. # All rights reserved. @@ -142,6 +142,8 @@ define TF_R0 offsetof(struct trapframe, tf_r0) define TF_R10 offsetof(struct trapframe, tf_r10) define TF_PC offsetof(struct trapframe, tf_pc) +define IF_PC offsetof(struct irqframe, if_pc) + define PROCSIZE sizeof(struct proc) define TRAPFRAMESIZE sizeof(struct trapframe) diff --git a/sys/arch/arm/arm32/irq_dispatch.S b/sys/arch/arm/arm32/irq_dispatch.S index 6812b057cc27..6a1b570e9e27 100644 --- a/sys/arch/arm/arm32/irq_dispatch.S +++ b/sys/arch/arm/arm32/irq_dispatch.S @@ -1,4 +1,4 @@ -/* $NetBSD: irq_dispatch.S,v 1.7 2005/12/11 12:16:41 christos Exp $ */ +/* $NetBSD: irq_dispatch.S,v 1.8 2007/03/09 19:21:58 thorpej Exp $ */ /* * Copyright (c) 2002 Fujitsu Component Limited @@ -94,6 +94,8 @@ .Lcurrent_intr_depth: .word _C_LABEL(current_intr_depth) +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS ASENTRY_NP(irq_entry) @@ -125,6 +127,8 @@ ASENTRY_NP(irq_entry) */ str r6, [r5] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT movs pc, lr /* Exit */ diff --git a/sys/arch/arm/conf/files.arm b/sys/arch/arm/conf/files.arm index 2ba9ff1b2f0a..97c13f85b0d3 100644 --- a/sys/arch/arm/conf/files.arm +++ b/sys/arch/arm/conf/files.arm @@ -1,4 +1,4 @@ -# $NetBSD: files.arm,v 1.82 2007/01/06 00:50:54 christos Exp $ +# $NetBSD: files.arm,v 1.83 2007/03/09 19:21:58 thorpej Exp $ # temporary define to allow easy moving to ../arch/arm/arm32 defflag ARM32 @@ -23,6 +23,9 @@ defflag opt_cpuoptions.h ARM9_CACHE_WRITE_THROUGH # Interrupt implementation header definition. defparam opt_arm_intr_impl.h ARM_INTR_IMPL +# ARM-specific debug options +defflag opt_arm_debug.h ARM_LOCK_CAS_DEBUG + # Board-specific bus_space(9) definitions defflag opt_arm_bus_space.h __BUS_SPACE_HAS_STREAM_METHODS @@ -115,6 +118,7 @@ file arch/arm/arm/cpufunc_asm_xscale.S cpu_xscale_80200 | cpu_xscale_pxa250 | cpu_xscale_pxa270 file arch/arm/arm/cpufunc_asm_ixp12x0.S cpu_ixp12x0 +file arch/arm/arm/lock_cas.S file arch/arm/arm/process_machdep.c file arch/arm/arm/procfs_machdep.c procfs file arch/arm/arm/sig_machdep.c diff --git a/sys/arch/arm/include/arm32/frame.h b/sys/arch/arm/include/arm32/frame.h index d4394083f5da..8593a720a21d 100644 --- a/sys/arch/arm/include/arm32/frame.h +++ b/sys/arch/arm/include/arm32/frame.h @@ -1,4 +1,4 @@ -/* $NetBSD: frame.h,v 1.14 2006/09/27 21:42:05 manu Exp $ */ +/* $NetBSD: frame.h,v 1.15 2007/03/09 19:21:58 thorpej Exp $ */ /* * Copyright (c) 1994-1997 Mark Brinicombe. @@ -111,6 +111,7 @@ void validate_trapframe __P((trapframe_t *, int)); #include "opt_compat_netbsd.h" #include "opt_execfmt.h" #include "opt_multiprocessor.h" +#include "opt_arm_debug.h" /* * AST_ALIGNMENT_FAULT_LOCALS and ENABLE_ALIGNMENT_FAULTS @@ -267,6 +268,55 @@ void validate_trapframe __P((trapframe_t *, int)); 2: #endif /* EXEC_AOUT */ +#ifdef ARM_LOCK_CAS_DEBUG +#define LOCK_CAS_DEBUG_LOCALS \ +.L_lock_cas_restart: ;\ + .word _C_LABEL(_lock_cas_restart) + +#if defined(__ARMEB__) +#define LOCK_CAS_DEBUG_COUNT_RESTART \ + ble 99f ;\ + ldr r0, .L_lock_cas_restart ;\ + ldmia r0, {r1-r2} /* load ev_count */ ;\ + adds r2, r2, #1 /* 64-bit incr (lo) */ ;\ + adc r1, r1, #0 /* 64-bit incr (hi) */ ;\ + stmia r0, {r1-r2} /* store ev_count */ +#else /* __ARMEB__ */ +#define LOCK_CAS_DEBUG_COUNT_RESTART \ + ble 99f ;\ + ldr r0, .L_lock_cas_restart ;\ + ldmia r0, {r1-r2} /* load ev_count */ ;\ + adds r1, r1, #1 /* 64-bit incr (lo) */ ;\ + adc r2, r2, #0 /* 64-bit incr (hi) */ ;\ + stmia r0, {r1-r2} /* store ev_count */ +#endif /* __ARMEB__ */ +#else /* ARM_LOCK_CAS_DEBUG */ +#define LOCK_CAS_DEBUG_LOCALS /* nothing */ +#define LOCK_CAS_DEBUG_COUNT_RESTART /* nothing */ +#endif /* ARM_LOCK_CAS_DEBUG */ + +#define LOCK_CAS_CHECK_LOCALS \ +.L_lock_cas: ;\ + .word _C_LABEL(_lock_cas) ;\ +.L_lock_cas_end: ;\ + .word _C_LABEL(_lock_cas_end) ;\ +LOCK_CAS_DEBUG_LOCALS + +#define LOCK_CAS_CHECK \ + ldr r0, [sp] /* get saved PSR */ ;\ + and r0, r0, #(PSR_MODE) /* check for SVC32 mode */ ;\ + teq r0, #(PSR_SVC32_MODE) ;\ + bne 99f /* nope, get out now */ ;\ + ldr r0, [sp, #(IF_PC)] ;\ + ldr r1, .L_lock_cas_end ;\ + cmp r0, r1 ;\ + bge 99f ;\ + ldr r1, .L_lock_cas ;\ + cmp r0, r1 ;\ + strgt r1, [sp, #(IF_PC)] ;\ + LOCK_CAS_DEBUG_COUNT_RESTART ;\ +99: + /* * ASM macros for pushing and pulling trapframes from the stack * diff --git a/sys/arch/arm/include/mutex.h b/sys/arch/arm/include/mutex.h index a933abd8d619..3376178a79d7 100644 --- a/sys/arch/arm/include/mutex.h +++ b/sys/arch/arm/include/mutex.h @@ -1,4 +1,4 @@ -/* $NetBSD: mutex.h,v 1.6 2007/03/09 11:30:28 skrll Exp $ */ +/* $NetBSD: mutex.h,v 1.7 2007/03/09 19:21:58 thorpej Exp $ */ /*- * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc. @@ -41,155 +41,68 @@ /* * The ARM mutex implementation is troublesome, because pre-v6 ARM lacks a - * compare-and-set operation. However, there aren't any MP pre-v6 ARM + * compare-and-swap operation. However, there aren't any MP pre-v6 ARM * systems to speak of. We are mostly concerned with atomicity with respect * to interrupts. * - * SMP for spin mutexes is easy - we don't need to know who owns the lock. - * For adaptive mutexes, we need an additional interlock. + * ARMv6, however, does have ldrex/strex, and can thus implement an MP-safe + * compare-and-swap. * - * Unfortunately, not all ARM kernels are linked at the same address, - * meaning we cannot safely overlay the interlock with the MSB of the - * owner field. - * - * For a mutex acquisition, we first grab the interlock and then set the - * owner field. - * - * There is room in the owners field for a waiters bit, but we don't do - * that because it would be hard to synchronize using one without a CAS - * operation. Because the waiters bit is only needed for adaptive mutexes, - * we instead use the lock that is normally used by spin mutexes to indicate - * waiters. - * - * Spin mutexes are initialized with the interlock held to cause the - * assembly stub to go through mutex_vector_enter(). - * - * When releasing an adaptive mutex, we first clear the owners field, and - * then check to see if the waiters byte is set. This ensures that there - * will always be someone to wake any sleeping waiters up (even it the mutex - * is acquired immediately after we release it, or if we are preempted - * immediatley after clearing the owners field). The setting or clearing of - * the waiters byte is serialized by the turnstile chain lock associated - * with the mutex. - * - * See comments in kern_mutex.c about releasing adaptive mutexes without - * an interlocking step. + * So, what we have done is impement simple mutexes using a compare-and-swap. + * We support pre-ARMv6 by implementing _lock_cas() as a restartable atomic + * sequence that is checked by the IRQ vector. MP-safe ARMv6 support will + * be added later. */ #ifndef __MUTEX_PRIVATE struct kmutex { uintptr_t mtx_pad1; - uint32_t mtx_pad2[2]; + uint32_t mtx_pad2; }; #else /* __MUTEX_PRIVATE */ struct kmutex { - volatile uintptr_t mtx_owner; /* 0-3 */ - __cpu_simple_lock_t mtx_interlock; /* 4 */ - __cpu_simple_lock_t mtx_lock; /* 5 */ - ipl_cookie_t mtx_ipl; /* 6 */ - uint8_t mtx_pad; /* 7 */ - uint32_t mtx_id; /* 8-11 */ + union { + /* Adaptive mutex */ + volatile uintptr_t mtxa_owner; /* 0-3 */ + + /* Spin mutex */ + struct { + volatile uint8_t mtxs_dummy; + ipl_cookie_t mtxs_ipl; + __cpu_simple_lock_t mtxs_lock; + volatile uint8_t mtxs_unused; + } s; + } u; + volatile uint32_t mtx_id; /* 4-7 */ }; +#define mtx_owner u.mtxa_owner +#define mtx_ipl u.s.mtxs_ipl +#define mtx_lock u.s.mtxs_lock + #if 0 -#define __HAVE_MUTEX_STUBS 1 -#define __HAVE_SPIN_MUTEX_STUBS 1 +#define __HAVE_MUTEX_STUBS 1 +#define __HAVE_SPIN_MUTEX_STUBS 1 #endif +#define __HAVE_SIMPLE_MUTEXES 1 -static inline uintptr_t -MUTEX_OWNER(uintptr_t owner) -{ - return owner; -} +/* + * MUTEX_RECEIVE: no memory barrier required; we're synchronizing against + * interrupts, not multiple processors. + */ +#define MUTEX_RECEIVE(mtx) /* nothing */ -static inline int -MUTEX_OWNED(uintptr_t owner) -{ - return owner != 0; -} +/* + * MUTEX_GIVE: no memory barrier required; same reason. + */ +#define MUTEX_GIVE(mtx) /* nothing */ -static inline int -MUTEX_SET_WAITERS(kmutex_t *mtx, uintptr_t owner) -{ - (void)__cpu_simple_lock_try(&mtx->mtx_lock); - return mtx->mtx_owner != 0; -} +bool _lock_cas(volatile uintptr_t *, uintptr_t, uintptr_t); -static inline void -MUTEX_CLEAR_WAITERS(kmutex_t *mtx) -{ - __cpu_simple_unlock(&mtx->mtx_lock); -} - -static inline int -MUTEX_HAS_WAITERS(volatile kmutex_t *mtx) -{ - if (mtx->mtx_owner == 0) - return 0; - return mtx->mtx_lock == __SIMPLELOCK_LOCKED; -} - -static inline void -MUTEX_INITIALIZE_SPIN(kmutex_t *mtx, u_int id, int ipl) -{ - mtx->mtx_id = (id << 1) | 1; - mtx->mtx_ipl = makeiplcookie(ipl); - mtx->mtx_interlock = __SIMPLELOCK_LOCKED; - __cpu_simple_lock_init(&mtx->mtx_lock); -} - -static inline void -MUTEX_INITIALIZE_ADAPTIVE(kmutex_t *mtx, u_int id) -{ - mtx->mtx_id = (id << 1) | 0; - __cpu_simple_lock_init(&mtx->mtx_interlock); - __cpu_simple_lock_init(&mtx->mtx_lock); -} - -static inline void -MUTEX_DESTROY(kmutex_t *mtx) -{ - mtx->mtx_owner = (uintptr_t)-1L; - mtx->mtx_id = ~0; -} - -static inline u_int -MUTEX_GETID(kmutex_t *mtx) -{ - return mtx->mtx_id >> 1; -} - -static inline bool -MUTEX_SPIN_P(volatile kmutex_t *mtx) -{ - return (mtx->mtx_id & 1) == 1; -} - -static inline bool -MUTEX_ADAPTIVE_P(volatile kmutex_t *mtx) -{ - return (mtx->mtx_id & 1) == 0; -} - -static inline int -MUTEX_ACQUIRE(kmutex_t *mtx, uintptr_t curthread) -{ - if (!__cpu_simple_lock_try(&mtx->mtx_interlock)) - return 0; - mtx->mtx_owner = curthread; - return 1; -} - -static inline void -MUTEX_RELEASE(kmutex_t *mtx) -{ - mtx->mtx_owner = 0; - __cpu_simple_unlock(&mtx->mtx_lock); - __cpu_simple_unlock(&mtx->mtx_interlock); -} +#define MUTEX_CAS(p, o, n) _lock_cas((p), (o), (n)) #endif /* __MUTEX_PRIVATE */ diff --git a/sys/arch/arm/iomd/iomd_irq.S b/sys/arch/arm/iomd/iomd_irq.S index 7686962f7017..2908ad1a55e7 100644 --- a/sys/arch/arm/iomd/iomd_irq.S +++ b/sys/arch/arm/iomd/iomd_irq.S @@ -1,4 +1,4 @@ -/* $NetBSD: iomd_irq.S,v 1.5 2005/12/11 12:16:47 christos Exp $ */ +/* $NetBSD: iomd_irq.S,v 1.6 2007/03/09 19:21:58 thorpej Exp $ */ /* * Copyright (c) 1994-1998 Mark Brinicombe. @@ -96,6 +96,8 @@ Lcurrent_intr_depth: Lspl_masks: .word _C_LABEL(spl_masks) +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS /* @@ -337,6 +339,8 @@ exitirq: sub r1, r1, #1 str r1, [r0] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT diff --git a/sys/arch/arm/ofw/ofw_irq.S b/sys/arch/arm/ofw/ofw_irq.S index 379a73e61bfa..c4be022c310c 100644 --- a/sys/arch/arm/ofw/ofw_irq.S +++ b/sys/arch/arm/ofw/ofw_irq.S @@ -1,4 +1,4 @@ -/* $NetBSD: ofw_irq.S,v 1.6 2007/03/08 20:48:39 matt Exp $ */ +/* $NetBSD: ofw_irq.S,v 1.7 2007/03/09 19:21:59 thorpej Exp $ */ /* * Copyright (c) 1994-1998 Mark Brinicombe. @@ -93,6 +93,8 @@ Lirq_entry: Lofwirqstk: /* hack */ .word ofwirqstk + 4096 +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS /* @@ -325,6 +327,8 @@ nextirq: sub r1, r1, #1 str r1, [r0] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT movs pc, lr /* Exit */ diff --git a/sys/arch/arm/sa11x0/sa11x0_irq.S b/sys/arch/arm/sa11x0/sa11x0_irq.S index 125c2ce4265c..eb67fc37872b 100644 --- a/sys/arch/arm/sa11x0/sa11x0_irq.S +++ b/sys/arch/arm/sa11x0/sa11x0_irq.S @@ -1,4 +1,4 @@ -/* $NetBSD: sa11x0_irq.S,v 1.9 2006/03/05 11:30:58 peter Exp $ */ +/* $NetBSD: sa11x0_irq.S,v 1.10 2007/03/09 19:21:59 thorpej Exp $ */ /* * Copyright (c) 1998 Mark Brinicombe. @@ -67,6 +67,8 @@ Ldbg_str: .asciz "irq_entry %x %x\n" #endif +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS /* @@ -244,6 +246,8 @@ nextirq: sub r1, r1, #1 str r1, [r0] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT diff --git a/sys/arch/arm/xscale/i80200_irq.S b/sys/arch/arm/xscale/i80200_irq.S index fad2a66ef240..807e93230990 100644 --- a/sys/arch/arm/xscale/i80200_irq.S +++ b/sys/arch/arm/xscale/i80200_irq.S @@ -1,4 +1,4 @@ -/* $NetBSD: i80200_irq.S,v 1.13 2005/12/11 12:16:51 christos Exp $ */ +/* $NetBSD: i80200_irq.S,v 1.14 2007/03/09 19:21:59 thorpej Exp $ */ /* * Copyright (c) 2002 Wasabi Systems, Inc. @@ -65,6 +65,8 @@ .word _C_LABEL(xscale_pmc_dispatch) #endif +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS ASENTRY_NP(irq_entry) @@ -128,6 +130,8 @@ ASENTRY_NP(irq_entry) sub r1, r1, #1 str r1, [r0] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT movs pc, lr /* Exit */ diff --git a/sys/arch/shark/isa/isa_irq.S b/sys/arch/shark/isa/isa_irq.S index ee3ce68e5e14..9699b1a6e323 100644 --- a/sys/arch/shark/isa/isa_irq.S +++ b/sys/arch/shark/isa/isa_irq.S @@ -1,4 +1,4 @@ -/* $NetBSD: isa_irq.S,v 1.6 2007/03/08 20:48:39 matt Exp $ */ +/* $NetBSD: isa_irq.S,v 1.7 2007/03/09 19:21:59 thorpej Exp $ */ /* * Copyright 1997 @@ -289,6 +289,8 @@ nextirq: sub r1, r1, #1 str r1, [r0] + LOCK_CAS_CHECK + DO_AST_AND_RESTORE_ALIGNMENT_FAULTS PULLFRAMEFROMSVCANDEXIT @@ -301,6 +303,8 @@ Lspl_mask: Lcurrent_mask: .word _C_LABEL(current_mask) /* irq's that are usable */ +LOCK_CAS_CHECK_LOCALS + AST_ALIGNMENT_FAULT_LOCALS