atomic.h revision 144761
1129198Scognet/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (C) 2003-2004 Olivier Houchard 5129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe 6129198Scognet * Copyright (C) 1994 Brini 7129198Scognet * All rights reserved. 8129198Scognet * 9129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 10129198Scognet * 11129198Scognet * Redistribution and use in source and binary forms, with or without 12129198Scognet * modification, are permitted provided that the following conditions 13129198Scognet * are met: 14129198Scognet * 1. Redistributions of source code must retain the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer. 16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 17129198Scognet * notice, this list of conditions and the following disclaimer in the 18129198Scognet * documentation and/or other materials provided with the distribution. 19129198Scognet * 3. All advertising materials mentioning features or use of this software 20129198Scognet * must display the following acknowledgement: 21129198Scognet * This product includes software developed by Brini. 22129198Scognet * 4. The name of Brini may not be used to endorse or promote products 23129198Scognet * derived from this software without specific prior written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 26129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35129198Scognet * 36129198Scognet * $FreeBSD: head/sys/arm/include/atomic.h 144761 2005-04-07 22:03:04Z cognet $ 37129198Scognet */ 38129198Scognet 39129198Scognet#ifndef _MACHINE_ATOMIC_H_ 40129198Scognet#define _MACHINE_ATOMIC_H_ 41129198Scognet 42129198Scognet 43129198Scognet 44129198Scognet#ifndef _LOCORE 45129198Scognet 46129198Scognet#include <sys/types.h> 47129198Scognet 48129198Scognet#ifndef I32_bit 49129198Scognet#define I32_bit (1 << 7) /* IRQ disable */ 50129198Scognet#endif 51129198Scognet#ifndef F32_bit 52129198Scognet#define F32_bit (1 << 6) /* FIQ disable */ 53129198Scognet#endif 54129198Scognet 55129198Scognet#define __with_interrupts_disabled(expr) \ 56129198Scognet do { \ 57129198Scognet u_int cpsr_save, tmp; \ 58129198Scognet \ 59129198Scognet __asm __volatile( \ 60129198Scognet "mrs %0, cpsr;" \ 61129198Scognet "orr %1, %0, %2;" \ 62129198Scognet "msr cpsr_all, %1;" \ 63129198Scognet : "=r" (cpsr_save), "=r" (tmp) \ 64129198Scognet : "I" (I32_bit) \ 65129198Scognet : "cc" ); \ 66129198Scognet (expr); \ 67129198Scognet __asm __volatile( \ 68129198Scognet "msr cpsr_all, %0" \ 69129198Scognet : /* no output */ \ 70129198Scognet : "r" (cpsr_save) \ 71129198Scognet : "cc" ); \ 72129198Scognet } while(0) 73129198Scognet 74144761Scognet#define ARM_RAS_START 0xe0000004 75144761Scognet#define ARM_RAS_END 0xe0000008 76144761Scognet 77137222Scognetstatic __inline uint32_t 78137222Scognet__swp(uint32_t val, volatile uint32_t *ptr) 79129198Scognet{ 80137222Scognet __asm __volatile("swp %0, %1, [%2]" 81139021Scognet : "=&r" (val) : "r" (val) , "r" (ptr) : "memory"); 82137222Scognet return (val); 83129198Scognet} 84129198Scognet 85137222Scognet 86144761Scognet#ifdef _KERNEL 87129198Scognetstatic __inline void 88137222Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask) 89129198Scognet{ 90144761Scognet __with_interrupts_disabled(*address |= setmask); 91129198Scognet} 92129198Scognet 93129198Scognetstatic __inline void 94129198Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 95129198Scognet{ 96144761Scognet __with_interrupts_disabled(*address &= ~clearmask); 97129198Scognet} 98129198Scognet 99144761Scognetstatic __inline u_int32_t 100144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 101129198Scognet{ 102144761Scognet int ret; 103144761Scognet 104144761Scognet __with_interrupts_disabled( 105144761Scognet { 106144761Scognet if (*p == cmpval) { 107144761Scognet *p = newval; 108144761Scognet ret = 1; 109144761Scognet } else { 110144761Scognet ret = 0; 111144761Scognet } 112144761Scognet }); 113144761Scognet return (ret); 114129198Scognet} 115129198Scognet 116129198Scognetstatic __inline void 117144761Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val) 118129198Scognet{ 119144761Scognet __with_interrupts_disabled(*p += val); 120129198Scognet} 121129198Scognet 122144761Scognetstatic __inline void 123144761Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 124129198Scognet{ 125144761Scognet __with_interrupts_disabled(*p -= val); 126129198Scognet} 127129198Scognet 128144761Scognet#else /* !_KERNEL */ 129144761Scognet 130129198Scognetstatic __inline u_int32_t 131144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 132129198Scognet{ 133144761Scognet register int done, ras_start; 134144761Scognet 135144761Scognet __asm __volatile("1:\n" 136144761Scognet "mov %0, #0xe0000008\n" 137144761Scognet "adr %1, 2f\n" 138144761Scognet "str %1, [%0]\n" 139144761Scognet "adr %1, 1b\n" 140144761Scognet "mov %0, #0xe0000004\n" 141144761Scognet "str %1, [%0]\n" 142144761Scognet "ldr %1, [%2]\n" 143144761Scognet "cmp %1, %3\n" 144144761Scognet "streq %4, [%2]\n" 145144761Scognet "2:\n" 146144761Scognet "moveq %1, #1\n" 147144761Scognet "movne %1, #0\n" 148144761Scognet : "=r" (ras_start), "=r" (done) 149144761Scognet ,"+r" (p), "+r" (cmpval), "+r" (newval)); 150137282Scognet return (done); 151129198Scognet} 152129198Scognet 153129198Scognetstatic __inline void 154129198Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val) 155129198Scognet{ 156144761Scognet int ras_start, start; 157144761Scognet 158144761Scognet __asm __volatile("1:\n" 159144761Scognet "mov %0, #0xe0000008\n" 160144761Scognet "adr %1, 2f\n" 161144761Scognet "str %1, [%0]\n" 162144761Scognet "adr %1, 1b\n" 163144761Scognet "mov %0, #0xe0000004\n" 164144761Scognet "str %1, [%0]\n" 165144761Scognet "ldr %1, [%2]\n" 166144761Scognet "add %1, %1, %3\n" 167144761Scognet "str %1, [%2]\n" 168144761Scognet "2:\n" 169144761Scognet : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val)); 170129198Scognet} 171129198Scognet 172129198Scognetstatic __inline void 173129198Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 174129198Scognet{ 175144761Scognet int ras_start, start; 176144761Scognet 177144761Scognet __asm __volatile("1:\n" 178144761Scognet "mov %0, #0xe0000008\n" 179144761Scognet "adr %1, 2f\n" 180144761Scognet "str %1, [%0]\n" 181144761Scognet "adr %1, 1b\n" 182144761Scognet "mov %0, #0xe0000004\n" 183144761Scognet "str %1, [%0]\n" 184144761Scognet "ldr %1, [%2]\n" 185144761Scognet "sub %1, %1, %3\n" 186144761Scognet "str %1, [%2]\n" 187144761Scognet "2:\n" 188144761Scognet : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val)); 189129198Scognet} 190129198Scognet 191144761Scognetstatic __inline void 192144761Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask) 193144761Scognet{ 194144761Scognet int ras_start, start; 195144761Scognet 196144761Scognet __asm __volatile("1:\n" 197144761Scognet "mov %0, #0xe0000008\n" 198144761Scognet "adr %1, 2f\n" 199144761Scognet "str %1, [%0]\n" 200144761Scognet "adr %1, 1b\n" 201144761Scognet "mov %0, #0xe0000004\n" 202144761Scognet "str %1, [%0]\n" 203144761Scognet "ldr %1, [%2]\n" 204144761Scognet "orr %1, %1, %3\n" 205144761Scognet "str %1, [%2]\n" 206144761Scognet "2:\n" 207144761Scognet : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask)); 208144761Scognet} 209144761Scognet 210144761Scognetstatic __inline void 211144761Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 212144761Scognet{ 213144761Scognet int ras_start, start; 214144761Scognet 215144761Scognet __asm __volatile("1:\n" 216144761Scognet "mov %0, #0xe0000008\n" 217144761Scognet "adr %1, 2f\n" 218144761Scognet "str %1, [%0]\n" 219144761Scognet "adr %1, 1b\n" 220144761Scognet "mov %0, #0xe0000004\n" 221144761Scognet "str %1, [%0]\n" 222144761Scognet "ldr %1, [%2]\n" 223144761Scognet "bic %1, %1, %3\n" 224144761Scognet "str %1, [%2]\n" 225144761Scognet "2:\n" 226144761Scognet : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask)); 227144761Scognet 228144761Scognet} 229144761Scognet#endif /* _KERNEL */ 230144761Scognet 231144761Scognetstatic __inline int 232144761Scognetatomic_load_32(volatile uint32_t *v) 233144761Scognet{ 234144761Scognet 235144761Scognet return (*v); 236144761Scognet} 237144761Scognet 238144761Scognetstatic __inline void 239144761Scognetatomic_store_32(volatile uint32_t *dst, uint32_t src) 240144761Scognet{ 241144761Scognet *dst = src; 242144761Scognet} 243144761Scognet 244144761Scognetstatic __inline uint32_t 245144761Scognetatomic_readandclear_32(volatile u_int32_t *p) 246144761Scognet{ 247144761Scognet 248144761Scognet return (__swp(0, p)); 249144761Scognet} 250144761Scognet 251137222Scognet#undef __with_interrupts_disabled 252129198Scognet 253137222Scognet#endif /* _LOCORE */ 254129198Scognet 255129198Scognet 256137222Scognet#define atomic_set_rel_int atomic_set_32 257137222Scognet#define atomic_set_int atomic_set_32 258137222Scognet#define atomic_readandclear_int atomic_readandclear_32 259137222Scognet#define atomic_clear_int atomic_clear_32 260137222Scognet#define atomic_subtract_int atomic_subtract_32 261137222Scognet#define atomic_subtract_rel_int atomic_subtract_32 262137222Scognet#define atomic_subtract_acq_int atomic_subtract_32 263137222Scognet#define atomic_add_int atomic_add_32 264137222Scognet#define atomic_add_rel_int atomic_add_32 265137222Scognet#define atomic_add_acq_int atomic_add_32 266137222Scognet#define atomic_cmpset_int atomic_cmpset_32 267137222Scognet#define atomic_cmpset_rel_int atomic_cmpset_32 268137222Scognet#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 269137222Scognet#define atomic_cmpset_acq_int atomic_cmpset_32 270137222Scognet#define atomic_cmpset_acq_ptr atomic_cmpset_ptr 271137222Scognet#define atomic_store_rel_ptr atomic_store_ptr 272137222Scognet#define atomic_store_rel_int atomic_store_32 273137222Scognet#define atomic_cmpset_rel_32 atomic_cmpset_32 274137222Scognet#define atomic_smpset_rel_ptr atomic_cmpset_ptr 275137222Scognet#define atomic_load_acq_int atomic_load_32 276137222Scognet#define atomic_clear_ptr(ptr, bit) atomic_clear_32( \ 277137222Scognet (volatile uint32_t *)ptr, (uint32_t)bit) 278137222Scognet#define atomic_store_ptr(ptr, bit) atomic_store_32( \ 279137222Scognet (volatile uint32_t *)ptr, (uint32_t)bit) 280137222Scognet#define atomic_cmpset_ptr(dst, exp, s) atomic_cmpset_32( \ 281137222Scognet (volatile uint32_t *)dst, (uint32_t)exp, (uint32_t)s) 282137222Scognet#define atomic_set_ptr(ptr, src) atomic_set_32( \ 283137222Scognet (volatile uint32_t *)ptr, (uint32_t)src) 284129198Scognet 285129198Scognet#endif /* _MACHINE_ATOMIC_H_ */ 286