xref: /minix3/sys/arch/x86/include/lock.h (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
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