1/* $NetBSD: atomic_cas.S,v 1.6 2008/04/28 20:22:52 martin Exp $ */ 2 3/*- 4 * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran and Jason R. Thorpe. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "atomic_op_asm.h" 33 34#if defined(_KERNEL) 35 36#include <machine/psl.h> 37 38#include "opt_multiprocessor.h" 39 40#define DISABLE_INTERRUPTS \ 41 rd %psr, %o4 /* disable interrupts */;\ 42 or %o4, PSR_PIL, %o5 ;\ 43 wr %o5, 0, %psr ;\ 44 nop ;\ 45 nop ;\ 46 nop 47 48#define RESTORE_INTERRUPTS \ 49 wr %o4, 0, %psr /* enable interrupts */ ;\ 50 nop ;\ 51 nop ;\ 52 nop 53 54#else /* _KERNEL */ 55 56#define MULTIPROCESSOR 1 57#define DISABLE_INTERRUPTS /* nothing */ 58#define RESTORE_INTERRUPTS /* nothing */ 59 60#endif /* _KERNEL */ 61 62#if defined(MULTIPROCESSOR) 63 .section .bss 64 .align 1024 65OTYPE(_C_LABEL(_atomic_cas_locktab)) 66_C_LABEL(_atomic_cas_locktab): 67 .space 1024 68 69#define ACQUIRE_INTERLOCK \ 70 DISABLE_INTERRUPTS ;\ 71 srl %o0, 3, %o5 /* get lock address */ ;\ 72 and %o5, 1023, %o5 ;\ 73 sethi %hi(_C_LABEL(_atomic_cas_locktab)), %o3 ;\ 74 add %o5, %o3, %o5 ;\ 75 ;\ 76 /* %o5 has interlock address */ ;\ 77 ;\ 781: ldstub [%o5], %o3 /* acquire lock */ ;\ 79 tst %o3 ;\ 80 bz,a 2f ;\ 81 nop ;\ 82 nop ;\ 83 nop ;\ 84 b,a 1b /* spin */ ;\ 85 nop ;\ 86 /* We now hold the interlock */ ;\ 872: 88 89#define RELEASE_INTERLOCK \ 90 stb %g0, [%o5] /* release interlock */ ;\ 91 RESTORE_INTERRUPTS 92 93#else /* ! MULTIPROCESSOR */ 94 95#define ACQUIRE_INTERLOCK DISABLE_INTERRUPTS 96 97#define RELEASE_INTERLOCK RESTORE_INTERRUPTS 98 99#endif /* MULTIPROCESSOR */ 100 101 .text 102 103/* 104 * The v7 and v8 SPARC doesn't have compare-and-swap, so we block interrupts 105 * and use an interlock. 106 * 107 * XXX On single CPU systems, this should use a restartable sequence: 108 * XXX there we don't need the overhead of interlocking. 109 * 110 * XXX NOTE! The interlock trick only works if EVERYTHING writes to 111 * XXX the memory cell through this code path! 112 */ 113ENTRY_NOPROFILE(_atomic_cas_32) 114 ACQUIRE_INTERLOCK 115 ! %o4 has saved PSR value 116 ! %o5 has interlock address 117 118 ld [%o0], %o3 ! get old value 119 cmp %o1, %o3 ! old == new? 120 beq,a 3f ! yes, do the store 121 st %o2, [%o0] ! (in the delay slot) 122 1233: RELEASE_INTERLOCK 124 125 retl 126 mov %o3, %o0 ! return old value 127 128ATOMIC_OP_ALIAS(atomic_cas_32,_atomic_cas_32) 129ATOMIC_OP_ALIAS(atomic_cas_uint,_atomic_cas_32) 130STRONG_ALIAS(_atomic_cas_uint,_atomic_cas_32) 131ATOMIC_OP_ALIAS(atomic_cas_ulong,_atomic_cas_32) 132STRONG_ALIAS(_atomic_cas_ulong,_atomic_cas_32) 133ATOMIC_OP_ALIAS(atomic_cas_ptr,_atomic_cas_32) 134STRONG_ALIAS(_atomic_cas_ptr,_atomic_cas_32) 135 136ATOMIC_OP_ALIAS(atomic_cas_32_ni,_atomic_cas_32) 137STRONG_ALIAS(_atomic_cas_32_ni,_atomic_cas_32) 138ATOMIC_OP_ALIAS(atomic_cas_uint_ni,_atomic_cas_32) 139STRONG_ALIAS(_atomic_cas_uint_ni,_atomic_cas_32) 140ATOMIC_OP_ALIAS(atomic_cas_ulong_ni,_atomic_cas_32) 141STRONG_ALIAS(_atomic_cas_ulong_ni,_atomic_cas_32) 142ATOMIC_OP_ALIAS(atomic_cas_ptr_ni,_atomic_cas_32) 143STRONG_ALIAS(_atomic_cas_ptr_ni,_atomic_cas_32) 144