1*84d9c625SLionel Sambuc /* $NetBSD: lock.h,v 1.27 2013/01/22 22:09:44 christos Exp $ */
21cd76c75SBen Gras
31cd76c75SBen Gras /*-
41cd76c75SBen Gras * Copyright (c) 2000, 2006 The NetBSD Foundation, Inc.
51cd76c75SBen Gras * All rights reserved.
61cd76c75SBen Gras *
71cd76c75SBen Gras * This code is derived from software contributed to The NetBSD Foundation
81cd76c75SBen Gras * by Jason R. Thorpe and Andrew Doran.
91cd76c75SBen Gras *
101cd76c75SBen Gras * Redistribution and use in source and binary forms, with or without
111cd76c75SBen Gras * modification, are permitted provided that the following conditions
121cd76c75SBen Gras * are met:
131cd76c75SBen Gras * 1. Redistributions of source code must retain the above copyright
141cd76c75SBen Gras * notice, this list of conditions and the following disclaimer.
151cd76c75SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
161cd76c75SBen Gras * notice, this list of conditions and the following disclaimer in the
171cd76c75SBen Gras * documentation and/or other materials provided with the distribution.
181cd76c75SBen Gras *
191cd76c75SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201cd76c75SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211cd76c75SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221cd76c75SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231cd76c75SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241cd76c75SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251cd76c75SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261cd76c75SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271cd76c75SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281cd76c75SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291cd76c75SBen Gras * POSSIBILITY OF SUCH DAMAGE.
301cd76c75SBen Gras */
311cd76c75SBen Gras
321cd76c75SBen Gras /*
331cd76c75SBen Gras * Machine-dependent spin lock operations.
341cd76c75SBen Gras */
351cd76c75SBen Gras
361cd76c75SBen Gras #ifndef _X86_LOCK_H_
371cd76c75SBen Gras #define _X86_LOCK_H_
381cd76c75SBen Gras
391cd76c75SBen Gras #include <sys/param.h>
401cd76c75SBen Gras
411cd76c75SBen Gras static __inline int
__SIMPLELOCK_LOCKED_P(__cpu_simple_lock_t * __ptr)421cd76c75SBen Gras __SIMPLELOCK_LOCKED_P(__cpu_simple_lock_t *__ptr)
431cd76c75SBen Gras {
441cd76c75SBen Gras return *__ptr == __SIMPLELOCK_LOCKED;
451cd76c75SBen Gras }
461cd76c75SBen Gras
471cd76c75SBen Gras static __inline int
__SIMPLELOCK_UNLOCKED_P(__cpu_simple_lock_t * __ptr)481cd76c75SBen Gras __SIMPLELOCK_UNLOCKED_P(__cpu_simple_lock_t *__ptr)
491cd76c75SBen Gras {
501cd76c75SBen Gras return *__ptr == __SIMPLELOCK_UNLOCKED;
511cd76c75SBen Gras }
521cd76c75SBen Gras
531cd76c75SBen Gras static __inline void
__cpu_simple_lock_set(__cpu_simple_lock_t * __ptr)541cd76c75SBen Gras __cpu_simple_lock_set(__cpu_simple_lock_t *__ptr)
551cd76c75SBen Gras {
561cd76c75SBen Gras
571cd76c75SBen Gras *__ptr = __SIMPLELOCK_LOCKED;
581cd76c75SBen Gras }
591cd76c75SBen Gras
601cd76c75SBen Gras static __inline void
__cpu_simple_lock_clear(__cpu_simple_lock_t * __ptr)611cd76c75SBen Gras __cpu_simple_lock_clear(__cpu_simple_lock_t *__ptr)
621cd76c75SBen Gras {
631cd76c75SBen Gras
641cd76c75SBen Gras *__ptr = __SIMPLELOCK_UNLOCKED;
651cd76c75SBen Gras }
661cd76c75SBen Gras
671cd76c75SBen Gras #ifdef _HARDKERNEL
681cd76c75SBen Gras # include <machine/cpufunc.h>
691cd76c75SBen Gras # define SPINLOCK_SPIN_HOOK /* nothing */
701cd76c75SBen Gras # ifdef SPINLOCK_BACKOFF_HOOK
711cd76c75SBen Gras # undef SPINLOCK_BACKOFF_HOOK
721cd76c75SBen Gras # endif
731cd76c75SBen Gras # define SPINLOCK_BACKOFF_HOOK x86_pause()
74*84d9c625SLionel Sambuc # define SPINLOCK_INLINE
75*84d9c625SLionel Sambuc #else /* !_HARDKERNEL */
76*84d9c625SLionel Sambuc # define SPINLOCK_BODY
77*84d9c625SLionel Sambuc # define SPINLOCK_INLINE static __inline __unused
78*84d9c625SLionel Sambuc #endif /* _HARDKERNEL */
791cd76c75SBen Gras
80*84d9c625SLionel Sambuc SPINLOCK_INLINE void __cpu_simple_lock_init(__cpu_simple_lock_t *);
81*84d9c625SLionel Sambuc SPINLOCK_INLINE void __cpu_simple_lock(__cpu_simple_lock_t *);
82*84d9c625SLionel Sambuc SPINLOCK_INLINE int __cpu_simple_lock_try(__cpu_simple_lock_t *);
83*84d9c625SLionel Sambuc SPINLOCK_INLINE void __cpu_simple_unlock(__cpu_simple_lock_t *);
841cd76c75SBen Gras
85*84d9c625SLionel Sambuc #ifdef SPINLOCK_BODY
86*84d9c625SLionel Sambuc SPINLOCK_INLINE void
__cpu_simple_lock_init(__cpu_simple_lock_t * lockp)871cd76c75SBen Gras __cpu_simple_lock_init(__cpu_simple_lock_t *lockp)
881cd76c75SBen Gras {
891cd76c75SBen Gras
901cd76c75SBen Gras *lockp = __SIMPLELOCK_UNLOCKED;
911cd76c75SBen Gras __insn_barrier();
921cd76c75SBen Gras }
931cd76c75SBen Gras
94*84d9c625SLionel Sambuc SPINLOCK_INLINE int
__cpu_simple_lock_try(__cpu_simple_lock_t * lockp)951cd76c75SBen Gras __cpu_simple_lock_try(__cpu_simple_lock_t *lockp)
961cd76c75SBen Gras {
971cd76c75SBen Gras uint8_t val;
981cd76c75SBen Gras
991cd76c75SBen Gras val = __SIMPLELOCK_LOCKED;
1001cd76c75SBen Gras __asm volatile ("xchgb %0,(%2)" :
1011cd76c75SBen Gras "=qQ" (val)
1021cd76c75SBen Gras :"0" (val), "r" (lockp));
1031cd76c75SBen Gras __insn_barrier();
1041cd76c75SBen Gras return val == __SIMPLELOCK_UNLOCKED;
1051cd76c75SBen Gras }
1061cd76c75SBen Gras
107*84d9c625SLionel Sambuc SPINLOCK_INLINE void
__cpu_simple_lock(__cpu_simple_lock_t * lockp)1081cd76c75SBen Gras __cpu_simple_lock(__cpu_simple_lock_t *lockp)
1091cd76c75SBen Gras {
1101cd76c75SBen Gras
1111cd76c75SBen Gras while (!__cpu_simple_lock_try(lockp))
1121cd76c75SBen Gras /* nothing */;
1131cd76c75SBen Gras __insn_barrier();
1141cd76c75SBen Gras }
1151cd76c75SBen Gras
1161cd76c75SBen Gras /*
1171cd76c75SBen Gras * Note on x86 memory ordering
1181cd76c75SBen Gras *
1191cd76c75SBen Gras * When releasing a lock we must ensure that no stores or loads from within
1201cd76c75SBen Gras * the critical section are re-ordered by the CPU to occur outside of it:
1211cd76c75SBen Gras * they must have completed and be visible to other processors once the lock
1221cd76c75SBen Gras * has been released.
1231cd76c75SBen Gras *
1241cd76c75SBen Gras * NetBSD usually runs with the kernel mapped (via MTRR) in a WB (write
1251cd76c75SBen Gras * back) memory region. In that case, memory ordering on x86 platforms
1261cd76c75SBen Gras * looks like this:
1271cd76c75SBen Gras *
1281cd76c75SBen Gras * i386 All loads/stores occur in instruction sequence.
1291cd76c75SBen Gras *
1301cd76c75SBen Gras * i486 All loads/stores occur in instruction sequence. In
1311cd76c75SBen Gras * Pentium exceptional circumstances, loads can be re-ordered around
1321cd76c75SBen Gras * stores, but for the purposes of releasing a lock it does
1331cd76c75SBen Gras * not matter. Stores may not be immediately visible to other
1341cd76c75SBen Gras * processors as they can be buffered. However, since the
1351cd76c75SBen Gras * stores are buffered in order the lock release will always be
1361cd76c75SBen Gras * the last operation in the critical section that becomes
1371cd76c75SBen Gras * visible to other CPUs.
1381cd76c75SBen Gras *
1391cd76c75SBen Gras * Pentium Pro The "Intel 64 and IA-32 Architectures Software Developer's
1401cd76c75SBen Gras * onwards Manual" volume 3A (order number 248966) says that (1) "Reads
1411cd76c75SBen Gras * can be carried out speculatively and in any order" and (2)
1421cd76c75SBen Gras * "Reads can pass buffered stores, but the processor is
1431cd76c75SBen Gras * self-consistent.". This would be a problem for the below,
1441cd76c75SBen Gras * and would mandate a locked instruction cycle or load fence
1451cd76c75SBen Gras * before releasing the simple lock.
1461cd76c75SBen Gras *
1471cd76c75SBen Gras * The "Intel Pentium 4 Processor Optimization" guide (order
1481cd76c75SBen Gras * number 253668-022US) says: "Loads can be moved before stores
1491cd76c75SBen Gras * that occurred earlier in the program if they are not
1501cd76c75SBen Gras * predicted to load from the same linear address.". This is
1511cd76c75SBen Gras * not a problem since the only loads that can be re-ordered
1521cd76c75SBen Gras * take place once the lock has been released via a store.
1531cd76c75SBen Gras *
1541cd76c75SBen Gras * The above two documents seem to contradict each other,
1551cd76c75SBen Gras * however with the exception of early steppings of the Pentium
1561cd76c75SBen Gras * Pro, the second document is closer to the truth: a store
1571cd76c75SBen Gras * will always act as a load fence for all loads that precede
1581cd76c75SBen Gras * the store in instruction order.
1591cd76c75SBen Gras *
1601cd76c75SBen Gras * Again, note that stores can be buffered and will not always
1611cd76c75SBen Gras * become immediately visible to other CPUs: they are however
1621cd76c75SBen Gras * buffered in order.
1631cd76c75SBen Gras *
1641cd76c75SBen Gras * AMD64 Stores occur in order and are buffered. Loads can be
1651cd76c75SBen Gras * reordered, however stores act as load fences, meaning that
1661cd76c75SBen Gras * loads can not be reordered around stores.
1671cd76c75SBen Gras */
168*84d9c625SLionel Sambuc SPINLOCK_INLINE void
__cpu_simple_unlock(__cpu_simple_lock_t * lockp)1691cd76c75SBen Gras __cpu_simple_unlock(__cpu_simple_lock_t *lockp)
1701cd76c75SBen Gras {
1711cd76c75SBen Gras
1721cd76c75SBen Gras __insn_barrier();
1731cd76c75SBen Gras *lockp = __SIMPLELOCK_UNLOCKED;
1741cd76c75SBen Gras }
1751cd76c75SBen Gras
176*84d9c625SLionel Sambuc #endif /* SPINLOCK_BODY */
1771cd76c75SBen Gras
1781cd76c75SBen Gras #endif /* _X86_LOCK_H_ */
179