1/*-
   2 * SPDX-License-Identifier: BSD-2-Clause
   3 *
   4 * Copyright (c) 2008 Marcel Moolenaar
   5 * Copyright (c) 2001 Benno Rice
   6 * Copyright (c) 2001 David E. O'Brien
   7 * Copyright (c) 1998 Doug Rabson
   8 * All rights reserved.
   9 *
  10 * Redistribution and use in source and binary forms, with or without
  11 * modification, are permitted provided that the following conditions
  12 * are met:
  13 * 1. Redistributions of source code must retain the above copyright
  14 *    notice, this list of conditions and the following disclaimer.
  15 * 2. Redistributions in binary form must reproduce the above copyright
  16 *    notice, this list of conditions and the following disclaimer in the
  17 *    documentation and/or other materials provided with the distribution.
  18 *
  19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29 * SUCH DAMAGE.
  30 */
  31
  32#ifndef _MACHINE_ATOMIC_H_
  33#define	_MACHINE_ATOMIC_H_
  34
  35#include <sys/atomic_common.h>
  36
  37#ifndef __powerpc64__
  38#include <sys/_atomic64e.h>
  39#endif
  40
  41/*
  42 * The __ATOMIC_REL/ACQ() macros provide memory barriers only in conjunction
  43 * with the atomic lXarx/stXcx. sequences below. They are not exposed outside
  44 * of this file. See also Appendix B.2 of Book II of the architecture manual.
  45 *
  46 * Note that not all Book-E processors accept the light-weight sync variant.
  47 * In particular, early models of E500 cores are known to wedge. Bank on all
  48 * 64-bit capable CPUs to accept lwsync properly and pressimize 32-bit CPUs
  49 * to use the heavier-weight sync.
  50 */
  51
  52#ifdef __powerpc64__
  53#define mb()		__asm __volatile("sync" : : : "memory")
  54#define rmb()		__asm __volatile("lwsync" : : : "memory")
  55#define wmb()		__asm __volatile("lwsync" : : : "memory")
  56#define __ATOMIC_REL()	__asm __volatile("lwsync" : : : "memory")
  57#define __ATOMIC_ACQ()	__asm __volatile("isync" : : : "memory")
  58#else
  59#define mb()		__asm __volatile("sync" : : : "memory")
  60#define rmb()		__asm __volatile("sync" : : : "memory")
  61#define wmb()		__asm __volatile("sync" : : : "memory")
  62#define __ATOMIC_REL()	__asm __volatile("sync" : : : "memory")
  63#define __ATOMIC_ACQ()	__asm __volatile("isync" : : : "memory")
  64#endif
  65
  66static __inline void
  67powerpc_lwsync(void)
  68{
  69
  70#ifdef __powerpc64__
  71	__asm __volatile("lwsync" : : : "memory");
  72#else
  73	__asm __volatile("sync" : : : "memory");
  74#endif
  75}
  76
  77/*
  78 * atomic_add(p, v)
  79 * { *p += v; }
  80 */
  81
  82#define __atomic_add_int(p, v, t)				\
  83    __asm __volatile(						\
  84	"1:	lwarx	%0, 0, %2\n"				\
  85	"	add	%0, %3, %0\n"				\
  86	"	stwcx.	%0, 0, %2\n"				\
  87	"	bne-	1b\n"					\
  88	: "=&r" (t), "=m" (*p)					\
  89	: "r" (p), "r" (v), "m" (*p)				\
  90	: "cr0", "memory")					\
  91    /* __atomic_add_int */
  92
  93#ifdef __powerpc64__
  94#define __atomic_add_long(p, v, t)				\
  95    __asm __volatile(						\
  96	"1:	ldarx	%0, 0, %2\n"				\
  97	"	add	%0, %3, %0\n"				\
  98	"	stdcx.	%0, 0, %2\n"				\
  99	"	bne-	1b\n"					\
 100	: "=&r" (t), "=m" (*p)					\
 101	: "r" (p), "r" (v), "m" (*p)				\
 102	: "cr0", "memory")					\
 103    /* __atomic_add_long */
 104#else
 105#define	__atomic_add_long(p, v, t)				\
 106    __asm __volatile(						\
 107	"1:	lwarx	%0, 0, %2\n"				\
 108	"	add	%0, %3, %0\n"				\
 109	"	stwcx.	%0, 0, %2\n"				\
 110	"	bne-	1b\n"					\
 111	: "=&r" (t), "=m" (*p)					\
 112	: "r" (p), "r" (v), "m" (*p)				\
 113	: "cr0", "memory")					\
 114    /* __atomic_add_long */
 115#endif
 116
 117#define	_ATOMIC_ADD(type)					\
 118    static __inline void					\
 119    atomic_add_##type(volatile u_##type *p, u_##type v) {	\
 120	u_##type t;						\
 121	__atomic_add_##type(p, v, t);				\
 122    }								\
 123								\
 124    static __inline void					\
 125    atomic_add_acq_##type(volatile u_##type *p, u_##type v) {	\
 126	u_##type t;						\
 127	__atomic_add_##type(p, v, t);				\
 128	__ATOMIC_ACQ();						\
 129    }								\
 130								\
 131    static __inline void					\
 132    atomic_add_rel_##type(volatile u_##type *p, u_##type v) {	\
 133	u_##type t;						\
 134	__ATOMIC_REL();						\
 135	__atomic_add_##type(p, v, t);				\
 136    }								\
 137    /* _ATOMIC_ADD */
 138
 139_ATOMIC_ADD(int)
 140_ATOMIC_ADD(long)
 141
 142#define	atomic_add_32		atomic_add_int
 143#define	atomic_add_acq_32	atomic_add_acq_int
 144#define	atomic_add_rel_32	atomic_add_rel_int
 145
 146#ifdef __powerpc64__
 147#define	atomic_add_64		atomic_add_long
 148#define	atomic_add_acq_64	atomic_add_acq_long
 149#define	atomic_add_rel_64	atomic_add_rel_long
 150
 151#define	atomic_add_ptr		atomic_add_long
 152#define	atomic_add_acq_ptr	atomic_add_acq_long
 153#define	atomic_add_rel_ptr	atomic_add_rel_long
 154#else
 155#define	atomic_add_ptr		atomic_add_int
 156#define	atomic_add_acq_ptr	atomic_add_acq_int
 157#define	atomic_add_rel_ptr	atomic_add_rel_int
 158#endif
 159#undef _ATOMIC_ADD
 160#undef __atomic_add_long
 161#undef __atomic_add_int
 162
 163/*
 164 * atomic_clear(p, v)
 165 * { *p &= ~v; }
 166 */
 167
 168#define __atomic_clear_int(p, v, t)				\
 169    __asm __volatile(						\
 170	"1:	lwarx	%0, 0, %2\n"				\
 171	"	andc	%0, %0, %3\n"				\
 172	"	stwcx.	%0, 0, %2\n"				\
 173	"	bne-	1b\n"					\
 174	: "=&r" (t), "=m" (*p)					\
 175	: "r" (p), "r" (v), "m" (*p)				\
 176	: "cr0", "memory")					\
 177    /* __atomic_clear_int */
 178
 179#ifdef __powerpc64__
 180#define __atomic_clear_long(p, v, t)				\
 181    __asm __volatile(						\
 182	"1:	ldarx	%0, 0, %2\n"				\
 183	"	andc	%0, %0, %3\n"				\
 184	"	stdcx.	%0, 0, %2\n"				\
 185	"	bne-	1b\n"					\
 186	: "=&r" (t), "=m" (*p)					\
 187	: "r" (p), "r" (v), "m" (*p)				\
 188	: "cr0", "memory")					\
 189    /* __atomic_clear_long */
 190#else
 191#define	__atomic_clear_long(p, v, t)				\
 192    __asm __volatile(						\
 193	"1:	lwarx	%0, 0, %2\n"				\
 194	"	andc	%0, %0, %3\n"				\
 195	"	stwcx.	%0, 0, %2\n"				\
 196	"	bne-	1b\n"					\
 197	: "=&r" (t), "=m" (*p)					\
 198	: "r" (p), "r" (v), "m" (*p)				\
 199	: "cr0", "memory")					\
 200    /* __atomic_clear_long */
 201#endif
 202
 203#define	_ATOMIC_CLEAR(type)					\
 204    static __inline void					\
 205    atomic_clear_##type(volatile u_##type *p, u_##type v) {	\
 206	u_##type t;						\
 207	__atomic_clear_##type(p, v, t);				\
 208    }								\
 209								\
 210    static __inline void					\
 211    atomic_clear_acq_##type(volatile u_##type *p, u_##type v) {	\
 212	u_##type t;						\
 213	__atomic_clear_##type(p, v, t);				\
 214	__ATOMIC_ACQ();						\
 215    }								\
 216								\
 217    static __inline void					\
 218    atomic_clear_rel_##type(volatile u_##type *p, u_##type v) {	\
 219	u_##type t;						\
 220	__ATOMIC_REL();						\
 221	__atomic_clear_##type(p, v, t);				\
 222    }								\
 223    /* _ATOMIC_CLEAR */
 224
 225_ATOMIC_CLEAR(int)
 226_ATOMIC_CLEAR(long)
 227
 228#define	atomic_clear_32		atomic_clear_int
 229#define	atomic_clear_acq_32	atomic_clear_acq_int
 230#define	atomic_clear_rel_32	atomic_clear_rel_int
 231
 232#ifdef __powerpc64__
 233#define	atomic_clear_64		atomic_clear_long
 234#define	atomic_clear_acq_64	atomic_clear_acq_long
 235#define	atomic_clear_rel_64	atomic_clear_rel_long
 236
 237#define	atomic_clear_ptr	atomic_clear_long
 238#define	atomic_clear_acq_ptr	atomic_clear_acq_long
 239#define	atomic_clear_rel_ptr	atomic_clear_rel_long
 240#else
 241#define	atomic_clear_ptr	atomic_clear_int
 242#define	atomic_clear_acq_ptr	atomic_clear_acq_int
 243#define	atomic_clear_rel_ptr	atomic_clear_rel_int
 244#endif
 245#undef _ATOMIC_CLEAR
 246#undef __atomic_clear_long
 247#undef __atomic_clear_int
 248
 249/*
 250 * atomic_cmpset(p, o, n)
 251 */
 252/* TODO -- see below */
 253
 254/*
 255 * atomic_load_acq(p)
 256 */
 257/* TODO -- see below */
 258
 259/*
 260 * atomic_readandclear(p)
 261 */
 262/* TODO -- see below */
 263
 264/*
 265 * atomic_set(p, v)
 266 * { *p |= v; }
 267 */
 268
 269#define __atomic_set_int(p, v, t)				\
 270    __asm __volatile(						\
 271	"1:	lwarx	%0, 0, %2\n"				\
 272	"	or	%0, %3, %0\n"				\
 273	"	stwcx.	%0, 0, %2\n"				\
 274	"	bne-	1b\n"					\
 275	: "=&r" (t), "=m" (*p)					\
 276	: "r" (p), "r" (v), "m" (*p)				\
 277	: "cr0", "memory")					\
 278    /* __atomic_set_int */
 279
 280#ifdef __powerpc64__
 281#define __atomic_set_long(p, v, t)				\
 282    __asm __volatile(						\
 283	"1:	ldarx	%0, 0, %2\n"				\
 284	"	or	%0, %3, %0\n"				\
 285	"	stdcx.	%0, 0, %2\n"				\
 286	"	bne-	1b\n"					\
 287	: "=&r" (t), "=m" (*p)					\
 288	: "r" (p), "r" (v), "m" (*p)				\
 289	: "cr0", "memory")					\
 290    /* __atomic_set_long */
 291#else
 292#define	__atomic_set_long(p, v, t)				\
 293    __asm __volatile(						\
 294	"1:	lwarx	%0, 0, %2\n"				\
 295	"	or	%0, %3, %0\n"				\
 296	"	stwcx.	%0, 0, %2\n"				\
 297	"	bne-	1b\n"					\
 298	: "=&r" (t), "=m" (*p)					\
 299	: "r" (p), "r" (v), "m" (*p)				\
 300	: "cr0", "memory")					\
 301    /* __atomic_set_long */
 302#endif
 303
 304#define	_ATOMIC_SET(type)					\
 305    static __inline void					\
 306    atomic_set_##type(volatile u_##type *p, u_##type v) {	\
 307	u_##type t;						\
 308	__atomic_set_##type(p, v, t);				\
 309    }								\
 310								\
 311    static __inline void					\
 312    atomic_set_acq_##type(volatile u_##type *p, u_##type v) {	\
 313	u_##type t;						\
 314	__atomic_set_##type(p, v, t);				\
 315	__ATOMIC_ACQ();						\
 316    }								\
 317								\
 318    static __inline void					\
 319    atomic_set_rel_##type(volatile u_##type *p, u_##type v) {	\
 320	u_##type t;						\
 321	__ATOMIC_REL();						\
 322	__atomic_set_##type(p, v, t);				\
 323    }								\
 324    /* _ATOMIC_SET */
 325
 326_ATOMIC_SET(int)
 327_ATOMIC_SET(long)
 328
 329#define	atomic_set_32		atomic_set_int
 330#define	atomic_set_acq_32	atomic_set_acq_int
 331#define	atomic_set_rel_32	atomic_set_rel_int
 332
 333#ifdef __powerpc64__
 334#define	atomic_set_64		atomic_set_long
 335#define	atomic_set_acq_64	atomic_set_acq_long
 336#define	atomic_set_rel_64	atomic_set_rel_long
 337
 338#define	atomic_set_ptr		atomic_set_long
 339#define	atomic_set_acq_ptr	atomic_set_acq_long
 340#define	atomic_set_rel_ptr	atomic_set_rel_long
 341#else
 342#define	atomic_set_ptr		atomic_set_int
 343#define	atomic_set_acq_ptr	atomic_set_acq_int
 344#define	atomic_set_rel_ptr	atomic_set_rel_int
 345#endif
 346#undef _ATOMIC_SET
 347#undef __atomic_set_long
 348#undef __atomic_set_int
 349
 350/*
 351 * atomic_subtract(p, v)
 352 * { *p -= v; }
 353 */
 354
 355#define __atomic_subtract_int(p, v, t)				\
 356    __asm __volatile(						\
 357	"1:	lwarx	%0, 0, %2\n"				\
 358	"	subf	%0, %3, %0\n"				\
 359	"	stwcx.	%0, 0, %2\n"				\
 360	"	bne-	1b\n"					\
 361	: "=&r" (t), "=m" (*p)					\
 362	: "r" (p), "r" (v), "m" (*p)				\
 363	: "cr0", "memory")					\
 364    /* __atomic_subtract_int */
 365
 366#ifdef __powerpc64__
 367#define __atomic_subtract_long(p, v, t)				\
 368    __asm __volatile(						\
 369	"1:	ldarx	%0, 0, %2\n"				\
 370	"	subf	%0, %3, %0\n"				\
 371	"	stdcx.	%0, 0, %2\n"				\
 372	"	bne-	1b\n"					\
 373	: "=&r" (t), "=m" (*p)					\
 374	: "r" (p), "r" (v), "m" (*p)				\
 375	: "cr0", "memory")					\
 376    /* __atomic_subtract_long */
 377#else
 378#define	__atomic_subtract_long(p, v, t)				\
 379    __asm __volatile(						\
 380	"1:	lwarx	%0, 0, %2\n"				\
 381	"	subf	%0, %3, %0\n"				\
 382	"	stwcx.	%0, 0, %2\n"				\
 383	"	bne-	1b\n"					\
 384	: "=&r" (t), "=m" (*p)					\
 385	: "r" (p), "r" (v), "m" (*p)				\
 386	: "cr0", "memory")					\
 387    /* __atomic_subtract_long */
 388#endif
 389
 390#define	_ATOMIC_SUBTRACT(type)						\
 391    static __inline void						\
 392    atomic_subtract_##type(volatile u_##type *p, u_##type v) {		\
 393	u_##type t;							\
 394	__atomic_subtract_##type(p, v, t);				\
 395    }									\
 396									\
 397    static __inline void						\
 398    atomic_subtract_acq_##type(volatile u_##type *p, u_##type v) {	\
 399	u_##type t;							\
 400	__atomic_subtract_##type(p, v, t);				\
 401	__ATOMIC_ACQ();							\
 402    }									\
 403									\
 404    static __inline void						\
 405    atomic_subtract_rel_##type(volatile u_##type *p, u_##type v) {	\
 406	u_##type t;							\
 407	__ATOMIC_REL();							\
 408	__atomic_subtract_##type(p, v, t);				\
 409    }									\
 410    /* _ATOMIC_SUBTRACT */
 411
 412_ATOMIC_SUBTRACT(int)
 413_ATOMIC_SUBTRACT(long)
 414
 415#define	atomic_subtract_32	atomic_subtract_int
 416#define	atomic_subtract_acq_32	atomic_subtract_acq_int
 417#define	atomic_subtract_rel_32	atomic_subtract_rel_int
 418
 419#ifdef __powerpc64__
 420#define	atomic_subtract_64	atomic_subtract_long
 421#define	atomic_subtract_acq_64	atomic_subract_acq_long
 422#define	atomic_subtract_rel_64	atomic_subtract_rel_long
 423
 424#define	atomic_subtract_ptr	atomic_subtract_long
 425#define	atomic_subtract_acq_ptr	atomic_subtract_acq_long
 426#define	atomic_subtract_rel_ptr	atomic_subtract_rel_long
 427#else
 428#define	atomic_subtract_ptr	atomic_subtract_int
 429#define	atomic_subtract_acq_ptr	atomic_subtract_acq_int
 430#define	atomic_subtract_rel_ptr	atomic_subtract_rel_int
 431#endif
 432#undef _ATOMIC_SUBTRACT
 433#undef __atomic_subtract_long
 434#undef __atomic_subtract_int
 435
 436/*
 437 * atomic_store_rel(p, v)
 438 */
 439/* TODO -- see below */
 440
 441/*
 442 * Old/original implementations that still need revisiting.
 443 */
 444
 445static __inline u_int
 446atomic_readandclear_int(volatile u_int *addr)
 447{
 448	u_int result,temp;
 449
 450	__asm __volatile (
 451		"\tsync\n"			/* drain writes */
 452		"1:\tlwarx %0, 0, %3\n\t"	/* load old value */
 453		"li %1, 0\n\t"			/* load new value */
 454		"stwcx. %1, 0, %3\n\t"      	/* attempt to store */
 455		"bne- 1b\n\t"			/* spin if failed */
 456		: "=&r"(result), "=&r"(temp), "=m" (*addr)
 457		: "r" (addr), "m" (*addr)
 458		: "cr0", "memory");
 459
 460	return (result);
 461}
 462
 463#ifdef __powerpc64__
 464static __inline u_long
 465atomic_readandclear_long(volatile u_long *addr)
 466{
 467	u_long result,temp;
 468
 469	__asm __volatile (
 470		"\tsync\n"			/* drain writes */
 471		"1:\tldarx %0, 0, %3\n\t"	/* load old value */
 472		"li %1, 0\n\t"			/* load new value */
 473		"stdcx. %1, 0, %3\n\t"      	/* attempt to store */
 474		"bne- 1b\n\t"			/* spin if failed */
 475		: "=&r"(result), "=&r"(temp), "=m" (*addr)
 476		: "r" (addr), "m" (*addr)
 477		: "cr0", "memory");
 478
 479	return (result);
 480}
 481#endif
 482
 483#define	atomic_readandclear_32		atomic_readandclear_int
 484
 485#ifdef __powerpc64__
 486#define	atomic_readandclear_64		atomic_readandclear_long
 487
 488#define	atomic_readandclear_ptr		atomic_readandclear_long
 489#else
 490static __inline u_long
 491atomic_readandclear_long(volatile u_long *addr)
 492{
 493
 494	return ((u_long)atomic_readandclear_int((volatile u_int *)addr));
 495}
 496
 497#define	atomic_readandclear_ptr		atomic_readandclear_int
 498#endif
 499
 500/*
 501 * We assume that a = b will do atomic loads and stores.
 502 */
 503#define	ATOMIC_STORE_LOAD(TYPE)					\
 504static __inline u_##TYPE					\
 505atomic_load_acq_##TYPE(volatile u_##TYPE *p)			\
 506{								\
 507	u_##TYPE v;						\
 508								\
 509	v = *p;							\
 510	powerpc_lwsync();					\
 511	return (v);						\
 512}								\
 513								\
 514static __inline void						\
 515atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)	\
 516{								\
 517								\
 518	powerpc_lwsync();					\
 519	*p = v;							\
 520}
 521
 522ATOMIC_STORE_LOAD(int)
 523
 524#define	atomic_load_acq_32	atomic_load_acq_int
 525#define	atomic_store_rel_32	atomic_store_rel_int
 526
 527#ifdef __powerpc64__
 528ATOMIC_STORE_LOAD(long)
 529
 530#define	atomic_load_acq_64	atomic_load_acq_long
 531#define	atomic_store_rel_64	atomic_store_rel_long
 532
 533#define	atomic_load_acq_ptr	atomic_load_acq_long
 534#define	atomic_store_rel_ptr	atomic_store_rel_long
 535#else
 536static __inline u_long
 537atomic_load_acq_long(volatile u_long *addr)
 538{
 539
 540	return ((u_long)atomic_load_acq_int((volatile u_int *)addr));
 541}
 542
 543static __inline void
 544atomic_store_rel_long(volatile u_long *addr, u_long val)
 545{
 546
 547	atomic_store_rel_int((volatile u_int *)addr, (u_int)val);
 548}
 549
 550#define	atomic_load_acq_ptr	atomic_load_acq_int
 551#define	atomic_store_rel_ptr	atomic_store_rel_int
 552#endif
 553#undef ATOMIC_STORE_LOAD
 554
 555/*
 556 * Atomically compare the value stored at *p with cmpval and if the
 557 * two values are equal, update the value of *p with newval. Returns
 558 * zero if the compare failed, nonzero otherwise.
 559 */
 560#ifdef ISA_206_ATOMICS
 561static __inline int
 562atomic_cmpset_char(volatile u_char *p, u_char cmpval, u_char newval)
 563{
 564	int	ret;
 565
 566	__asm __volatile (
 567		"1:\tlbarx %0, 0, %2\n\t"	/* load old value */
 568		"cmplw %3, %0\n\t"		/* compare */
 569		"bne- 2f\n\t"			/* exit if not equal */
 570		"stbcx. %4, 0, %2\n\t"      	/* attempt to store */
 571		"bne- 1b\n\t"			/* spin if failed */
 572		"li %0, 1\n\t"			/* success - retval = 1 */
 573		"b 3f\n\t"			/* we've succeeded */
 574		"2:\n\t"
 575		"stbcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
 576		"li %0, 0\n\t"			/* failure - retval = 0 */
 577		"3:\n\t"
 578		: "=&r" (ret), "=m" (*p)
 579		: "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
 580		: "cr0", "memory");
 581
 582	return (ret);
 583}
 584
 585static __inline int
 586atomic_cmpset_short(volatile u_short *p, u_short cmpval, u_short newval)
 587{
 588	int	ret;
 589
 590	__asm __volatile (
 591		"1:\tlharx %0, 0, %2\n\t"	/* load old value */
 592		"cmplw %3, %0\n\t"		/* compare */
 593		"bne- 2f\n\t"			/* exit if not equal */
 594		"sthcx. %4, 0, %2\n\t"      	/* attempt to store */
 595		"bne- 1b\n\t"			/* spin if failed */
 596		"li %0, 1\n\t"			/* success - retval = 1 */
 597		"b 3f\n\t"			/* we've succeeded */
 598		"2:\n\t"
 599		"sthcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
 600		"li %0, 0\n\t"			/* failure - retval = 0 */
 601		"3:\n\t"
 602		: "=&r" (ret), "=m" (*p)
 603		: "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
 604		: "cr0", "memory");
 605
 606	return (ret);
 607}
 608#else
 609static __inline int
 610atomic_cmpset_masked(uint32_t *p, uint32_t cmpval, uint32_t newval,
 611    uint32_t mask)
 612{
 613	int		ret;
 614	uint32_t	tmp;
 615
 616	__asm __volatile (
 617		"1:\tlwarx %2, 0, %3\n\t"	/* load old value */
 618		"and %0, %2, %7\n\t"
 619		"cmplw %4, %0\n\t"		/* compare */
 620		"bne- 2f\n\t"			/* exit if not equal */
 621		"andc %2, %2, %7\n\t"
 622		"or %2, %2, %5\n\t"
 623		"stwcx. %2, 0, %3\n\t"      	/* attempt to store */
 624		"bne- 1b\n\t"			/* spin if failed */
 625		"li %0, 1\n\t"			/* success - retval = 1 */
 626		"b 3f\n\t"			/* we've succeeded */
 627		"2:\n\t"
 628		"stwcx. %2, 0, %3\n\t"       	/* clear reservation (74xx) */
 629		"li %0, 0\n\t"			/* failure - retval = 0 */
 630		"3:\n\t"
 631		: "=&r" (ret), "=m" (*p), "+&r" (tmp)
 632		: "r" (p), "r" (cmpval), "r" (newval), "m" (*p),
 633		  "r" (mask)
 634		: "cr0", "memory");
 635
 636	return (ret);
 637}
 638
 639#define	_atomic_cmpset_masked_word(a,o,v,m) atomic_cmpset_masked(a, o, v, m)
 640#endif
 641
 642static __inline int
 643atomic_cmpset_int(volatile u_int* p, u_int cmpval, u_int newval)
 644{
 645	int	ret;
 646
 647	__asm __volatile (
 648		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
 649		"cmplw %3, %0\n\t"		/* compare */
 650		"bne- 2f\n\t"			/* exit if not equal */
 651		"stwcx. %4, 0, %2\n\t"      	/* attempt to store */
 652		"bne- 1b\n\t"			/* spin if failed */
 653		"li %0, 1\n\t"			/* success - retval = 1 */
 654		"b 3f\n\t"			/* we've succeeded */
 655		"2:\n\t"
 656		"stwcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
 657		"li %0, 0\n\t"			/* failure - retval = 0 */
 658		"3:\n\t"
 659		: "=&r" (ret), "=m" (*p)
 660		: "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
 661		: "cr0", "memory");
 662
 663	return (ret);
 664}
 665static __inline int
 666atomic_cmpset_long(volatile u_long* p, u_long cmpval, u_long newval)
 667{
 668	int ret;
 669
 670	__asm __volatile (
 671	    #ifdef __powerpc64__
 672		"1:\tldarx %0, 0, %2\n\t"	/* load old value */
 673		"cmpld %3, %0\n\t"		/* compare */
 674		"bne- 2f\n\t"			/* exit if not equal */
 675		"stdcx. %4, 0, %2\n\t"		/* attempt to store */
 676	    #else
 677		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
 678		"cmplw %3, %0\n\t"		/* compare */
 679		"bne- 2f\n\t"			/* exit if not equal */
 680		"stwcx. %4, 0, %2\n\t"		/* attempt to store */
 681	    #endif
 682		"bne- 1b\n\t"			/* spin if failed */
 683		"li %0, 1\n\t"			/* success - retval = 1 */
 684		"b 3f\n\t"			/* we've succeeded */
 685		"2:\n\t"
 686	    #ifdef __powerpc64__
 687		"stdcx. %0, 0, %2\n\t"		/* clear reservation (74xx) */
 688	    #else
 689		"stwcx. %0, 0, %2\n\t"		/* clear reservation (74xx) */
 690	    #endif
 691		"li %0, 0\n\t"			/* failure - retval = 0 */
 692		"3:\n\t"
 693		: "=&r" (ret), "=m" (*p)
 694		: "r" (p), "r" (cmpval), "r" (newval), "m" (*p)
 695		: "cr0", "memory");
 696
 697	return (ret);
 698}
 699
 700#define	ATOMIC_CMPSET_ACQ_REL(type) \
 701    static __inline int \
 702    atomic_cmpset_acq_##type(volatile u_##type *p, \
 703	    u_##type cmpval, u_##type newval)\
 704    {\
 705	u_##type retval; \
 706	retval = atomic_cmpset_##type(p, cmpval, newval);\
 707	__ATOMIC_ACQ();\
 708	return (retval);\
 709    }\
 710    static __inline int \
 711    atomic_cmpset_rel_##type(volatile u_##type *p, \
 712	    u_##type cmpval, u_##type newval)\
 713    {\
 714	__ATOMIC_REL();\
 715	return (atomic_cmpset_##type(p, cmpval, newval));\
 716    }\
 717    struct hack
 718
 719ATOMIC_CMPSET_ACQ_REL(int);
 720ATOMIC_CMPSET_ACQ_REL(long);
 721
 722#ifdef ISA_206_ATOMICS
 723#define	atomic_cmpset_8		atomic_cmpset_char
 724#endif
 725#define	atomic_cmpset_acq_8	atomic_cmpset_acq_char
 726#define	atomic_cmpset_rel_8	atomic_cmpset_rel_char
 727
 728#ifdef ISA_206_ATOMICS
 729#define	atomic_cmpset_16	atomic_cmpset_short
 730#endif
 731#define	atomic_cmpset_acq_16	atomic_cmpset_acq_short
 732#define	atomic_cmpset_rel_16	atomic_cmpset_rel_short
 733
 734#define	atomic_cmpset_32	atomic_cmpset_int
 735#define	atomic_cmpset_acq_32	atomic_cmpset_acq_int
 736#define	atomic_cmpset_rel_32	atomic_cmpset_rel_int
 737
 738#ifdef __powerpc64__
 739#define	atomic_cmpset_64	atomic_cmpset_long
 740#define	atomic_cmpset_acq_64	atomic_cmpset_acq_long
 741#define	atomic_cmpset_rel_64	atomic_cmpset_rel_long
 742
 743#define	atomic_cmpset_ptr	atomic_cmpset_long
 744#define	atomic_cmpset_acq_ptr	atomic_cmpset_acq_long
 745#define	atomic_cmpset_rel_ptr	atomic_cmpset_rel_long
 746#else
 747#define	atomic_cmpset_ptr	atomic_cmpset_int
 748#define	atomic_cmpset_acq_ptr	atomic_cmpset_acq_int
 749#define	atomic_cmpset_rel_ptr	atomic_cmpset_rel_int
 750#endif
 751
 752/*
 753 * Atomically compare the value stored at *p with *cmpval and if the
 754 * two values are equal, update the value of *p with newval. Returns
 755 * zero if the compare failed and sets *cmpval to the read value from *p,
 756 * nonzero otherwise.
 757 */
 758#ifdef ISA_206_ATOMICS
 759static __inline int
 760atomic_fcmpset_char(volatile u_char *p, u_char *cmpval, u_char newval)
 761{
 762	int	ret;
 763
 764	__asm __volatile (
 765		"lbarx %0, 0, %3\n\t"		/* load old value */
 766		"cmplw %4, %0\n\t"		/* compare */
 767		"bne- 1f\n\t"			/* exit if not equal */
 768		"stbcx. %5, 0, %3\n\t"      	/* attempt to store */
 769		"bne- 1f\n\t"			/* exit if failed */
 770		"li %0, 1\n\t"			/* success - retval = 1 */
 771		"b 2f\n\t"			/* we've succeeded */
 772		"1:\n\t"
 773		"stbcx. %0, 0, %3\n\t"       	/* clear reservation (74xx) */
 774		"stbx %0, 0, %7\n\t"
 775		"li %0, 0\n\t"			/* failure - retval = 0 */
 776		"2:\n\t"
 777		: "=&r" (ret), "=m" (*p), "=m" (*cmpval)
 778		: "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
 779		: "cr0", "memory");
 780
 781	return (ret);
 782}
 783
 784static __inline int
 785atomic_fcmpset_short(volatile u_short *p, u_short *cmpval, u_short newval)
 786{
 787	int	ret;
 788
 789	__asm __volatile (
 790		"lharx %0, 0, %3\n\t"		/* load old value */
 791		"cmplw %4, %0\n\t"		/* compare */
 792		"bne- 1f\n\t"			/* exit if not equal */
 793		"sthcx. %5, 0, %3\n\t"      	/* attempt to store */
 794		"bne- 1f\n\t"			/* exit if failed */
 795		"li %0, 1\n\t"			/* success - retval = 1 */
 796		"b 2f\n\t"			/* we've succeeded */
 797		"1:\n\t"
 798		"sthcx. %0, 0, %3\n\t"       	/* clear reservation (74xx) */
 799		"sthx %0, 0, %7\n\t"
 800		"li %0, 0\n\t"			/* failure - retval = 0 */
 801		"2:\n\t"
 802		: "=&r" (ret), "=m" (*p), "=m" (*cmpval)
 803		: "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
 804		: "cr0", "memory");
 805
 806	return (ret);
 807}
 808#endif	/* ISA_206_ATOMICS */
 809
 810static __inline int
 811atomic_fcmpset_int(volatile u_int *p, u_int *cmpval, u_int newval)
 812{
 813	int	ret;
 814
 815	__asm __volatile (
 816		"lwarx %0, 0, %3\n\t"		/* load old value */
 817		"cmplw %4, %0\n\t"		/* compare */
 818		"bne- 1f\n\t"			/* exit if not equal */
 819		"stwcx. %5, 0, %3\n\t"      	/* attempt to store */
 820		"bne- 1f\n\t"			/* exit if failed */
 821		"li %0, 1\n\t"			/* success - retval = 1 */
 822		"b 2f\n\t"			/* we've succeeded */
 823		"1:\n\t"
 824		"stwcx. %0, 0, %3\n\t"       	/* clear reservation (74xx) */
 825		"stwx %0, 0, %7\n\t"
 826		"li %0, 0\n\t"			/* failure - retval = 0 */
 827		"2:\n\t"
 828		: "=&r" (ret), "=m" (*p), "=m" (*cmpval)
 829		: "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
 830		: "cr0", "memory");
 831
 832	return (ret);
 833}
 834static __inline int
 835atomic_fcmpset_long(volatile u_long *p, u_long *cmpval, u_long newval)
 836{
 837	int ret;
 838
 839	__asm __volatile (
 840	    #ifdef __powerpc64__
 841		"ldarx %0, 0, %3\n\t"		/* load old value */
 842		"cmpld %4, %0\n\t"		/* compare */
 843		"bne- 1f\n\t"			/* exit if not equal */
 844		"stdcx. %5, 0, %3\n\t"		/* attempt to store */
 845	    #else
 846		"lwarx %0, 0, %3\n\t"		/* load old value */
 847		"cmplw %4, %0\n\t"		/* compare */
 848		"bne- 1f\n\t"			/* exit if not equal */
 849		"stwcx. %5, 0, %3\n\t"		/* attempt to store */
 850	    #endif
 851		"bne- 1f\n\t"			/* exit if failed */
 852		"li %0, 1\n\t"			/* success - retval = 1 */
 853		"b 2f\n\t"			/* we've succeeded */
 854		"1:\n\t"
 855	    #ifdef __powerpc64__
 856		"stdcx. %0, 0, %3\n\t"		/* clear reservation (74xx) */
 857		"stdx %0, 0, %7\n\t"
 858	    #else
 859		"stwcx. %0, 0, %3\n\t"		/* clear reservation (74xx) */
 860		"stwx %0, 0, %7\n\t"
 861	    #endif
 862		"li %0, 0\n\t"			/* failure - retval = 0 */
 863		"2:\n\t"
 864		: "=&r" (ret), "=m" (*p), "=m" (*cmpval)
 865		: "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval)
 866		: "cr0", "memory");
 867
 868	return (ret);
 869}
 870
 871#define	ATOMIC_FCMPSET_ACQ_REL(type) \
 872    static __inline int \
 873    atomic_fcmpset_acq_##type(volatile u_##type *p, \
 874	    u_##type *cmpval, u_##type newval)\
 875    {\
 876	u_##type retval; \
 877	retval = atomic_fcmpset_##type(p, cmpval, newval);\
 878	__ATOMIC_ACQ();\
 879	return (retval);\
 880    }\
 881    static __inline int \
 882    atomic_fcmpset_rel_##type(volatile u_##type *p, \
 883	    u_##type *cmpval, u_##type newval)\
 884    {\
 885	__ATOMIC_REL();\
 886	return (atomic_fcmpset_##type(p, cmpval, newval));\
 887    }\
 888    struct hack
 889
 890ATOMIC_FCMPSET_ACQ_REL(int);
 891ATOMIC_FCMPSET_ACQ_REL(long);
 892
 893#ifdef ISA_206_ATOMICS
 894#define	atomic_fcmpset_8	atomic_fcmpset_char
 895#endif
 896#define	atomic_fcmpset_acq_8	atomic_fcmpset_acq_char
 897#define	atomic_fcmpset_rel_8	atomic_fcmpset_rel_char
 898
 899#ifdef ISA_206_ATOMICS
 900#define	atomic_fcmpset_16	atomic_fcmpset_short
 901#endif
 902#define	atomic_fcmpset_acq_16	atomic_fcmpset_acq_short
 903#define	atomic_fcmpset_rel_16	atomic_fcmpset_rel_short
 904
 905#define	atomic_fcmpset_32	atomic_fcmpset_int
 906#define	atomic_fcmpset_acq_32	atomic_fcmpset_acq_int
 907#define	atomic_fcmpset_rel_32	atomic_fcmpset_rel_int
 908
 909#ifdef __powerpc64__
 910#define	atomic_fcmpset_64	atomic_fcmpset_long
 911#define	atomic_fcmpset_acq_64	atomic_fcmpset_acq_long
 912#define	atomic_fcmpset_rel_64	atomic_fcmpset_rel_long
 913
 914#define	atomic_fcmpset_ptr	atomic_fcmpset_long
 915#define	atomic_fcmpset_acq_ptr	atomic_fcmpset_acq_long
 916#define	atomic_fcmpset_rel_ptr	atomic_fcmpset_rel_long
 917#else
 918#define	atomic_fcmpset_ptr	atomic_fcmpset_int
 919#define	atomic_fcmpset_acq_ptr	atomic_fcmpset_acq_int
 920#define	atomic_fcmpset_rel_ptr	atomic_fcmpset_rel_int
 921#endif
 922
 923static __inline u_int
 924atomic_fetchadd_int(volatile u_int *p, u_int v)
 925{
 926	u_int value;
 927
 928	do {
 929		value = *p;
 930	} while (!atomic_cmpset_int(p, value, value + v));
 931	return (value);
 932}
 933
 934static __inline u_long
 935atomic_fetchadd_long(volatile u_long *p, u_long v)
 936{
 937	u_long value;
 938
 939	do {
 940		value = *p;
 941	} while (!atomic_cmpset_long(p, value, value + v));
 942	return (value);
 943}
 944
 945static __inline u_int
 946atomic_swap_32(volatile u_int *p, u_int v)
 947{
 948	u_int prev;
 949
 950	__asm __volatile(
 951	"1:	lwarx	%0,0,%2\n"
 952	"	stwcx.	%3,0,%2\n"
 953	"	bne-	1b\n"
 954	: "=&r" (prev), "+m" (*(volatile u_int *)p)
 955	: "r" (p), "r" (v)
 956	: "cr0", "memory");
 957
 958	return (prev);
 959}
 960
 961#ifdef __powerpc64__
 962static __inline u_long
 963atomic_swap_64(volatile u_long *p, u_long v)
 964{
 965	u_long prev;
 966
 967	__asm __volatile(
 968	"1:	ldarx	%0,0,%2\n"
 969	"	stdcx.	%3,0,%2\n"
 970	"	bne-	1b\n"
 971	: "=&r" (prev), "+m" (*(volatile u_long *)p)
 972	: "r" (p), "r" (v)
 973	: "cr0", "memory");
 974
 975	return (prev);
 976}
 977#endif
 978
 979#define	atomic_fetchadd_32	atomic_fetchadd_int
 980#define	atomic_swap_int		atomic_swap_32
 981
 982#ifdef __powerpc64__
 983#define	atomic_fetchadd_64	atomic_fetchadd_long
 984#define	atomic_swap_long	atomic_swap_64
 985#define	atomic_swap_ptr		atomic_swap_64
 986#else
 987#define	atomic_swap_long(p,v)	atomic_swap_32((volatile u_int *)(p), v)
 988#define	atomic_swap_ptr(p,v)	atomic_swap_32((volatile u_int *)(p), v)
 989#endif
 990
 991static __inline int
 992atomic_testandset_int(volatile u_int *p, u_int v)
 993{
 994	u_int m = (1u << (v & 0x1f));
 995	u_int res;
 996	u_int tmp;
 997
 998	__asm __volatile(
 999	"1:	lwarx	%0,0,%3\n"
1000	"	and	%1,%0,%4\n"
1001	"	or	%0,%0,%4\n"
1002	"	stwcx.	%0,0,%3\n"
1003	"	bne-	1b\n"
1004	: "=&r"(tmp), "=&r"(res), "+m"(*p)
1005	: "r"(p), "r"(m)
1006	: "cr0", "memory");
1007
1008	return (res != 0);
1009}
1010
1011static __inline int
1012atomic_testandclear_int(volatile u_int *p, u_int v)
1013{
1014	u_int m = (1u << (v & 0x1f));
1015	u_int res;
1016	u_int tmp;
1017
1018	__asm __volatile(
1019	"1:	lwarx	%0,0,%3\n"
1020	"	and	%1,%0,%4\n"
1021	"	andc	%0,%0,%4\n"
1022	"	stwcx.	%0,0,%3\n"
1023	"	bne-	1b\n"
1024	: "=&r"(tmp), "=&r"(res), "+m"(*p)
1025	: "r"(p), "r"(m)
1026	: "cr0", "memory");
1027
1028	return (res != 0);
1029}
1030
1031#ifdef __powerpc64__
1032static __inline int
1033atomic_testandset_long(volatile u_long *p, u_int v)
1034{
1035	u_long m = (1ul << (v & 0x3f));
1036	u_long res;
1037	u_long tmp;
1038
1039	__asm __volatile(
1040	"1:	ldarx	%0,0,%3\n"
1041	"	and	%1,%0,%4\n"
1042	"	or	%0,%0,%4\n"
1043	"	stdcx.	%0,0,%3\n"
1044	"	bne-	1b\n"
1045	: "=&r"(tmp), "=&r"(res), "+m"(*(volatile u_long *)p)
1046	: "r"(p), "r"(m)
1047	: "cr0", "memory");
1048
1049	return (res != 0);
1050}
1051
1052static __inline int
1053atomic_testandclear_long(volatile u_long *p, u_int v)
1054{
1055	u_long m = (1ul << (v & 0x3f));
1056	u_long res;
1057	u_long tmp;
1058
1059	__asm __volatile(
1060	"1:	ldarx	%0,0,%3\n"
1061	"	and	%1,%0,%4\n"
1062	"	andc	%0,%0,%4\n"
1063	"	stdcx.	%0,0,%3\n"
1064	"	bne-	1b\n"
1065	: "=&r"(tmp), "=&r"(res), "+m"(*p)
1066	: "r"(p), "r"(m)
1067	: "cr0", "memory");
1068
1069	return (res != 0);
1070}
1071#else
1072static __inline int
1073atomic_testandset_long(volatile u_long *p, u_int v)
1074{
1075	return (atomic_testandset_int((volatile u_int *)p, v));
1076}
1077
1078static __inline int
1079atomic_testandclear_long(volatile u_long *p, u_int v)
1080{
1081	return (atomic_testandclear_int((volatile u_int *)p, v));
1082}
1083#endif
1084
1085#define	atomic_testandclear_32	atomic_testandclear_int
1086#define	atomic_testandset_32	atomic_testandset_int
1087
1088static __inline int
1089atomic_testandset_acq_long(volatile u_long *p, u_int v)
1090{
1091	u_int a = atomic_testandset_long(p, v);
1092	__ATOMIC_ACQ();
1093	return (a);
1094}
1095
1096#define	atomic_testandclear_int		atomic_testandclear_int
1097#define	atomic_testandset_int		atomic_testandset_int
1098#define	atomic_testandclear_long	atomic_testandclear_long
1099#define	atomic_testandset_long		atomic_testandset_long
1100#define	atomic_testandset_acq_long	atomic_testandset_acq_long
1101
1102static __inline void
1103atomic_thread_fence_acq(void)
1104{
1105
1106	powerpc_lwsync();
1107}
1108
1109static __inline void
1110atomic_thread_fence_rel(void)
1111{
1112
1113	powerpc_lwsync();
1114}
1115
1116static __inline void
1117atomic_thread_fence_acq_rel(void)
1118{
1119
1120	powerpc_lwsync();
1121}
1122
1123static __inline void
1124atomic_thread_fence_seq_cst(void)
1125{
1126
1127	__asm __volatile("sync" : : : "memory");
1128}
1129
1130#ifndef ISA_206_ATOMICS
1131#include <sys/_atomic_subword.h>
1132#define	atomic_cmpset_char	atomic_cmpset_8
1133#define	atomic_cmpset_short	atomic_cmpset_16
1134#define	atomic_fcmpset_char	atomic_fcmpset_8
1135#define	atomic_fcmpset_short	atomic_fcmpset_16
1136#endif
1137
1138/* These need sys/_atomic_subword.h on non-ISA-2.06-atomic platforms. */
1139ATOMIC_CMPSET_ACQ_REL(char);
1140ATOMIC_CMPSET_ACQ_REL(short);
1141
1142ATOMIC_FCMPSET_ACQ_REL(char);
1143ATOMIC_FCMPSET_ACQ_REL(short);
1144
1145#undef __ATOMIC_REL
1146#undef __ATOMIC_ACQ
1147
1148#endif /* ! _MACHINE_ATOMIC_H_ */