11.23Sriastrad/*	$NetBSD: lock.h,v 1.23 2022/04/09 23:43:20 riastradh Exp $	*/
21.1Sthorpej
31.1Sthorpej/*-
41.10Sad * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc.
51.1Sthorpej * All rights reserved.
61.1Sthorpej *
71.1Sthorpej * This code is derived from software contributed to The NetBSD Foundation
81.10Sad * by Wayne Knowles and Andrew Doran.
91.1Sthorpej *
101.1Sthorpej * Redistribution and use in source and binary forms, with or without
111.1Sthorpej * modification, are permitted provided that the following conditions
121.1Sthorpej * are met:
131.1Sthorpej * 1. Redistributions of source code must retain the above copyright
141.1Sthorpej *    notice, this list of conditions and the following disclaimer.
151.1Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
161.1Sthorpej *    notice, this list of conditions and the following disclaimer in the
171.1Sthorpej *    documentation and/or other materials provided with the distribution.
181.1Sthorpej *
191.1Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sthorpej * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sthorpej * POSSIBILITY OF SUCH DAMAGE.
301.1Sthorpej */
311.1Sthorpej
321.1Sthorpej/*
331.10Sad * Machine-dependent spin lock operations for MIPS processors.
341.3Sgmcgarry *
351.10Sad * Note: R2000/R3000 doesn't have any atomic update instructions; this
361.10Sad * will cause problems for user applications using this header.
371.1Sthorpej */
381.1Sthorpej
391.1Sthorpej#ifndef _MIPS_LOCK_H_
401.1Sthorpej#define	_MIPS_LOCK_H_
411.3Sgmcgarry
421.17Spooka#include <sys/param.h>
431.17Spooka
441.22Sriastrad#include <sys/atomic.h>
451.22Sriastrad
461.13Sskrllstatic __inline int
471.20Schristos__SIMPLELOCK_LOCKED_P(const __cpu_simple_lock_t *__ptr)
481.13Sskrll{
491.18Smatt	return *__ptr != __SIMPLELOCK_UNLOCKED;
501.13Sskrll}
511.13Sskrll
521.13Sskrllstatic __inline int
531.20Schristos__SIMPLELOCK_UNLOCKED_P(const __cpu_simple_lock_t *__ptr)
541.13Sskrll{
551.13Sskrll	return *__ptr == __SIMPLELOCK_UNLOCKED;
561.13Sskrll}
571.13Sskrll
581.13Sskrllstatic __inline void
591.13Sskrll__cpu_simple_lock_clear(__cpu_simple_lock_t *__ptr)
601.13Sskrll{
611.13Sskrll	*__ptr = __SIMPLELOCK_UNLOCKED;
621.13Sskrll}
631.13Sskrll
641.13Sskrllstatic __inline void
651.13Sskrll__cpu_simple_lock_set(__cpu_simple_lock_t *__ptr)
661.13Sskrll{
671.13Sskrll	*__ptr = __SIMPLELOCK_LOCKED;
681.13Sskrll}
691.13Sskrll
701.17Spooka#ifndef _HARDKERNEL
711.3Sgmcgarry
721.8Sperrystatic __inline int
731.3Sgmcgarry__cpu_simple_lock_try(__cpu_simple_lock_t *lp)
741.3Sgmcgarry{
751.3Sgmcgarry	unsigned long t0, v0;
761.3Sgmcgarry
771.7Sperry	__asm volatile(
781.3Sgmcgarry		"# -- BEGIN __cpu_simple_lock_try\n"
791.3Sgmcgarry		"	.set push		\n"
801.3Sgmcgarry		"	.set mips2		\n"
811.3Sgmcgarry		"1:	ll	%0, %4		\n"
821.3Sgmcgarry		"	bnez	%0, 2f		\n"
831.21Ssimonb		"	 nop			\n"
841.3Sgmcgarry		"	li	%0, %3		\n"
851.3Sgmcgarry		"	sc	%0, %2		\n"
861.3Sgmcgarry		"	beqz	%0, 2f		\n"
871.21Ssimonb		"	 nop			\n"
881.3Sgmcgarry		"	li	%1, 1		\n"
891.3Sgmcgarry		"	sync			\n"
901.3Sgmcgarry		"	j	3f		\n"
911.21Ssimonb		"	 nop			\n"
921.3Sgmcgarry		"	nop			\n"
931.3Sgmcgarry		"2:	li	%1, 0		\n"
941.3Sgmcgarry		"3:				\n"
951.3Sgmcgarry		"	.set pop		\n"
961.3Sgmcgarry		"# -- END __cpu_simple_lock_try	\n"
971.3Sgmcgarry		: "=r" (t0), "=r" (v0), "+m" (*lp)
981.9Ssimonb		: "i" (__SIMPLELOCK_LOCKED), "m" (*lp));
991.3Sgmcgarry
1001.3Sgmcgarry	return (v0 != 0);
1011.3Sgmcgarry}
1021.3Sgmcgarry
1031.17Spooka#else	/* !_HARDKERNEL */
1041.10Sad
1051.18Smattu_int	_atomic_cas_uint(volatile u_int *, u_int, u_int);
1061.18Smattu_long	_atomic_cas_ulong(volatile u_long *, u_long, u_long);
1071.18Smattvoid *	_atomic_cas_ptr(volatile void *, void *, void *);
1081.10Sad
1091.10Sadstatic __inline int
1101.10Sad__cpu_simple_lock_try(__cpu_simple_lock_t *lp)
1111.10Sad{
1121.10Sad
1131.22Sriastrad	/*
1141.22Sriastrad	 * Successful _atomic_cas_uint functions as a load-acquire --
1151.22Sriastrad	 * on MP systems, it issues sync after the LL/SC CAS succeeds;
1161.22Sriastrad	 * on non-MP systems every load is a load-acquire so it's moot.
1171.23Sriastrad	 * This pairs with the membar_release and store sequence in
1181.22Sriastrad	 * __cpu_simple_unlock that functions as a store-release
1191.22Sriastrad	 * operation.
1201.22Sriastrad	 *
1211.22Sriastrad	 * NOTE: This applies only to _atomic_cas_uint (with the
1221.22Sriastrad	 * underscore), in sys/arch/mips/mips/lock_stubs_*.S.  Not true
1231.22Sriastrad	 * for atomic_cas_uint (without the underscore), from
1241.22Sriastrad	 * common/lib/libc/arch/mips/atomic/atomic_cas.S which does not
1251.22Sriastrad	 * imply a load-acquire.  It is unclear why these disagree.
1261.22Sriastrad	 */
1271.18Smatt	return _atomic_cas_uint(lp,
1281.15Sad	    __SIMPLELOCK_UNLOCKED, __SIMPLELOCK_LOCKED) ==
1291.15Sad	    __SIMPLELOCK_UNLOCKED;
1301.10Sad}
1311.10Sad
1321.17Spooka#endif	/* _HARDKERNEL */
1331.10Sad
1341.10Sadstatic __inline void
1351.10Sad__cpu_simple_lock_init(__cpu_simple_lock_t *lp)
1361.10Sad{
1371.10Sad
1381.10Sad	*lp = __SIMPLELOCK_UNLOCKED;
1391.10Sad}
1401.10Sad
1411.10Sadstatic __inline void
1421.10Sad__cpu_simple_lock(__cpu_simple_lock_t *lp)
1431.10Sad{
1441.10Sad
1451.18Smatt	while (!__cpu_simple_lock_try(lp)) {
1461.10Sad		while (*lp == __SIMPLELOCK_LOCKED)
1471.10Sad			/* spin */;
1481.18Smatt	}
1491.10Sad}
1501.10Sad
1511.8Sperrystatic __inline void
1521.3Sgmcgarry__cpu_simple_unlock(__cpu_simple_lock_t *lp)
1531.3Sgmcgarry{
1541.3Sgmcgarry
1551.22Sriastrad	/*
1561.23Sriastrad	 * The membar_release and then store functions as a
1571.23Sriastrad	 * store-release operation that pairs with the load-acquire
1581.23Sriastrad	 * operation in successful __cpu_simple_lock_try.
1591.22Sriastrad	 *
1601.22Sriastrad	 * Can't use atomic_store_release here because that's not
1611.22Sriastrad	 * available in userland at the moment.
1621.22Sriastrad	 */
1631.23Sriastrad	membar_release();
1641.10Sad	*lp = __SIMPLELOCK_UNLOCKED;
1651.22Sriastrad
1661.19Smatt#ifdef _MIPS_ARCH_OCTEONP
1671.22Sriastrad	/*
1681.22Sriastrad	 * On Cavium's recommendation, we issue an extra SYNCW that is
1691.22Sriastrad	 * not necessary for correct ordering because apparently stores
1701.22Sriastrad	 * can get stuck in Octeon store buffers for hundreds of
1711.22Sriastrad	 * thousands of cycles, according to the following note:
1721.22Sriastrad	 *
1731.22Sriastrad	 *	Programming Notes:
1741.22Sriastrad	 *	[...]
1751.22Sriastrad	 *	Core A (writer)
1761.22Sriastrad	 *	SW R1, DATA
1771.22Sriastrad	 *	LI R2, 1
1781.22Sriastrad	 *	SYNCW
1791.22Sriastrad	 *	SW R2, FLAG
1801.22Sriastrad	 *	SYNCW
1811.22Sriastrad	 *	[...]
1821.22Sriastrad	 *
1831.22Sriastrad	 *	The second SYNCW instruction executed by core A is not
1841.22Sriastrad	 *	necessary for correctness, but has very important
1851.22Sriastrad	 *	performance effects on OCTEON.  Without it, the store
1861.22Sriastrad	 *	to FLAG may linger in core A's write buffer before it
1871.22Sriastrad	 *	becomes visible to other cores.  (If core A is not
1881.22Sriastrad	 *	performing many stores, this may add hundreds of
1891.22Sriastrad	 *	thousands of cycles to the flag release time since the
1901.22Sriastrad	 *	OCTEON core normally retains stores to attempt to merge
1911.22Sriastrad	 *	them before sending the store on the CMB.)
1921.22Sriastrad	 *	Applications should include this second SYNCW
1931.22Sriastrad	 *	instruction after flag or lock releases.
1941.22Sriastrad	 *
1951.22Sriastrad	 * Cavium Networks OCTEON Plus CN50XX Hardware Reference
1961.22Sriastrad	 * Manual, July 2008, Appendix A, p. 943.
1971.22Sriastrad	 * https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/hactive/CN50XX-HRM-V0.99E.pdf
1981.22Sriastrad	 *
1991.22Sriastrad	 * XXX It might be prudent to put this into
2001.22Sriastrad	 * atomic_store_release itself.
2011.22Sriastrad	 */
2021.22Sriastrad	__asm volatile("syncw" ::: "memory");
2031.19Smatt#endif
2041.3Sgmcgarry}
2051.10Sad
2061.1Sthorpej#endif /* _MIPS_LOCK_H_ */
207