atomic.h revision 155391
1121054Semax/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */ 2121054Semax 3121054Semax/*- 4121054Semax * Copyright (C) 2003-2004 Olivier Houchard 5121054Semax * Copyright (C) 1994-1997 Mark Brinicombe 6121054Semax * Copyright (C) 1994 Brini 7121054Semax * All rights reserved. 8121054Semax * 9121054Semax * This code is derived from software written for Brini by Mark Brinicombe 10121054Semax * 11121054Semax * Redistribution and use in source and binary forms, with or without 12121054Semax * modification, are permitted provided that the following conditions 13121054Semax * are met: 14121054Semax * 1. Redistributions of source code must retain the above copyright 15121054Semax * notice, this list of conditions and the following disclaimer. 16121054Semax * 2. Redistributions in binary form must reproduce the above copyright 17121054Semax * notice, this list of conditions and the following disclaimer in the 18121054Semax * documentation and/or other materials provided with the distribution. 19121054Semax * 3. All advertising materials mentioning features or use of this software 20121054Semax * must display the following acknowledgement: 21121054Semax * This product includes software developed by Brini. 22121054Semax * 4. The name of Brini may not be used to endorse or promote products 23121054Semax * derived from this software without specific prior written permission. 24121054Semax * 25121054Semax * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 26121054Semax * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27121054Semax * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28121054Semax * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29121054Semax * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30121054Semax * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31121054Semax * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32121054Semax * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33121054Semax * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34121054Semax * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35121054Semax * 36121054Semax * $FreeBSD: head/sys/arm/include/atomic.h 155391 2006-02-06 18:29:05Z cognet $ 37121054Semax */ 38121054Semax 39121054Semax#ifndef _MACHINE_ATOMIC_H_ 40121054Semax#define _MACHINE_ATOMIC_H_ 41121054Semax 42121054Semax 43121054Semax 44121054Semax#ifndef _LOCORE 45121054Semax 46121054Semax#include <sys/types.h> 47121054Semax 48121054Semax#ifndef I32_bit 49121054Semax#define I32_bit (1 << 7) /* IRQ disable */ 50121054Semax#endif 51121054Semax#ifndef F32_bit 52121054Semax#define F32_bit (1 << 6) /* FIQ disable */ 53121054Semax#endif 54121054Semax 55121054Semax#define __with_interrupts_disabled(expr) \ 56121054Semax do { \ 57121054Semax u_int cpsr_save, tmp; \ 58121054Semax \ 59121054Semax __asm __volatile( \ 60121054Semax "mrs %0, cpsr;" \ 61121054Semax "orr %1, %0, %2;" \ 62121054Semax "msr cpsr_all, %1;" \ 63121054Semax : "=r" (cpsr_save), "=r" (tmp) \ 64121054Semax : "I" (I32_bit) \ 65121054Semax : "cc" ); \ 66121054Semax (expr); \ 67121054Semax __asm __volatile( \ 68121054Semax "msr cpsr_all, %0" \ 69121054Semax : /* no output */ \ 70121054Semax : "r" (cpsr_save) \ 71121054Semax : "cc" ); \ 72121054Semax } while(0) 73121054Semax 74121054Semax#define ARM_RAS_START 0xe0000004 75121054Semax#define ARM_RAS_END 0xe0000008 76121054Semax 77121054Semaxstatic __inline uint32_t 78121054Semax__swp(uint32_t val, volatile uint32_t *ptr) 79121054Semax{ 80121054Semax __asm __volatile("swp %0, %2, [%3]" 81121054Semax : "=&r" (val), "=m" (*ptr) 82121054Semax : "r" (val), "r" (ptr), "m" (*ptr) 83121054Semax : "memory"); 84121054Semax return (val); 85121054Semax} 86121054Semax 87121054Semax 88121054Semax#ifdef _KERNEL 89121054Semaxstatic __inline void 90121054Semaxatomic_set_32(volatile uint32_t *address, uint32_t setmask) 91121054Semax{ 92121054Semax __with_interrupts_disabled(*address |= setmask); 93121054Semax} 94121054Semax 95121054Semaxstatic __inline void 96121054Semaxatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 97121054Semax{ 98121054Semax __with_interrupts_disabled(*address &= ~clearmask); 99121054Semax} 100121054Semax 101121054Semaxstatic __inline u_int32_t 102121054Semaxatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 103121054Semax{ 104121054Semax int ret; 105121054Semax 106121054Semax __with_interrupts_disabled( 107121054Semax { 108121054Semax if (*p == cmpval) { 109121054Semax *p = newval; 110121054Semax ret = 1; 111121054Semax } else { 112121054Semax ret = 0; 113121054Semax } 114121054Semax }); 115121054Semax return (ret); 116121054Semax} 117121054Semax 118121054Semaxstatic __inline void 119121054Semaxatomic_add_32(volatile u_int32_t *p, u_int32_t val) 120121054Semax{ 121121054Semax __with_interrupts_disabled(*p += val); 122121054Semax} 123121054Semax 124121054Semaxstatic __inline void 125121054Semaxatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 126121054Semax{ 127121054Semax __with_interrupts_disabled(*p -= val); 128121054Semax} 129121054Semax 130121054Semaxstatic __inline uint32_t 131121054Semaxatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 132121054Semax{ 133121054Semax uint32_t value; 134121054Semax 135121054Semax __with_interrupts_disabled( 136121054Semax { 137121054Semax value = *p; 138121054Semax *p += v; 139121054Semax }); 140121054Semax return (value); 141121054Semax} 142121054Semax 143121054Semax#else /* !_KERNEL */ 144121054Semax 145121054Semaxstatic __inline u_int32_t 146121054Semaxatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 147121054Semax{ 148121054Semax register int done, ras_start; 149121054Semax 150121054Semax __asm __volatile("1:\n" 151121054Semax "mov %0, #0xe0000008\n" 152121054Semax "adr %1, 2f\n" 153121054Semax "str %1, [%0]\n" 154121054Semax "adr %1, 1b\n" 155121054Semax "mov %0, #0xe0000004\n" 156121054Semax "str %1, [%0]\n" 157121054Semax "ldr %1, [%2]\n" 158121054Semax "cmp %1, %3\n" 159121054Semax "streq %4, [%2]\n" 160121054Semax "2:\n" 161121054Semax "mov %1, #0\n" 162121054Semax "str %1, [%0]\n" 163121054Semax "moveq %1, #1\n" 164121054Semax "movne %1, #0\n" 165121054Semax : "=r" (ras_start), "=r" (done) 166121054Semax ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory"); 167121054Semax return (done); 168121054Semax} 169121054Semax 170121054Semaxstatic __inline void 171121054Semaxatomic_add_32(volatile u_int32_t *p, u_int32_t val) 172121054Semax{ 173121054Semax int ras_start, start; 174121054Semax 175121054Semax __asm __volatile("1:\n" 176121054Semax "mov %0, #0xe0000008\n" 177121054Semax "adr %1, 2f\n" 178121054Semax "str %1, [%0]\n" 179121054Semax "adr %1, 1b\n" 180121054Semax "mov %0, #0xe0000004\n" 181121054Semax "str %1, [%0]\n" 182121054Semax "ldr %1, [%2]\n" 183121054Semax "add %1, %1, %3\n" 184121054Semax "str %1, [%2]\n" 185121054Semax "2:\n" 186121054Semax "mov %1, #0\n" 187121054Semax "str %1, [%0]\n" 188121054Semax : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 189121054Semax : : "memory"); 190124305Semax} 191121054Semax 192121054Semaxstatic __inline void 193121054Semaxatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 194121054Semax{ 195121054Semax int ras_start, start; 196121054Semax 197121054Semax __asm __volatile("1:\n" 198121054Semax "mov %0, #0xe0000008\n" 199121054Semax "adr %1, 2f\n" 200121054Semax "str %1, [%0]\n" 201121054Semax "adr %1, 1b\n" 202121054Semax "mov %0, #0xe0000004\n" 203121054Semax "str %1, [%0]\n" 204121054Semax "ldr %1, [%2]\n" 205121054Semax "sub %1, %1, %3\n" 206121054Semax "str %1, [%2]\n" 207121054Semax "2:\n" 208121054Semax "mov %1, #0\n" 209121054Semax "str %1, [%0]\n" 210121054Semax 211121054Semax : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 212121054Semax : : "memory"); 213121054Semax} 214121054Semax 215121054Semaxstatic __inline void 216121054Semaxatomic_set_32(volatile uint32_t *address, uint32_t setmask) 217121054Semax{ 218121054Semax int ras_start, start; 219121054Semax 220121054Semax __asm __volatile("1:\n" 221121054Semax "mov %0, #0xe0000008\n" 222121054Semax "adr %1, 2f\n" 223121054Semax "str %1, [%0]\n" 224121054Semax "adr %1, 1b\n" 225121054Semax "mov %0, #0xe0000004\n" 226121054Semax "str %1, [%0]\n" 227121054Semax "ldr %1, [%2]\n" 228121054Semax "orr %1, %1, %3\n" 229121054Semax "str %1, [%2]\n" 230121054Semax "2:\n" 231121054Semax "mov %1, #0\n" 232121054Semax "str %1, [%0]\n" 233121054Semax 234121054Semax : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask) 235121054Semax : : "memory"); 236121054Semax} 237121054Semax 238121054Semaxstatic __inline void 239121054Semaxatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 240124305Semax{ 241121054Semax int ras_start, start; 242121054Semax 243121054Semax __asm __volatile("1:\n" 244121054Semax "mov %0, #0xe0000008\n" 245121054Semax "adr %1, 2f\n" 246121054Semax "str %1, [%0]\n" 247121054Semax "adr %1, 1b\n" 248121054Semax "mov %0, #0xe0000004\n" 249121054Semax "str %1, [%0]\n" 250121054Semax "ldr %1, [%2]\n" 251121054Semax "bic %1, %1, %3\n" 252121054Semax "str %1, [%2]\n" 253121054Semax "2:\n" 254121054Semax "mov %1, #0\n" 255121054Semax "str %1, [%0]\n" 256121054Semax : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask) 257121054Semax : : "memory"); 258124305Semax 259124305Semax} 260124305Semax 261121054Semaxstatic __inline uint32_t 262121054Semaxatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 263121054Semax{ 264121054Semax uint32_t ras_start, start; 265121054Semax 266124305Semax __asm __volatile("1:\n" 267124305Semax "mov %0, #0xe0000008\n" 268124305Semax "adr %1, 2f\n" 269124305Semax "str %1, [%0]\n" 270124305Semax "adr %1, 1b\n" 271124305Semax "mov %0, #0xe0000004\n" 272124305Semax "str %1, [%0]\n" 273124305Semax "ldr %1, [%2]\n" 274124305Semax "add %3, %1, %3\n" 275124305Semax "str %3, [%2]\n" 276124305Semax "2:\n" 277121054Semax "mov %3, #0\n" 278121054Semax "str %3, [%0]\n" 279121054Semax : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (v) 280121054Semax : : "memory"); 281121054Semax return (start); 282121054Semax} 283121054Semax 284124305Semax 285121054Semax#endif /* _KERNEL */ 286121054Semax 287121054Semaxstatic __inline int 288121054Semaxatomic_load_32(volatile uint32_t *v) 289121054Semax{ 290121054Semax 291124305Semax return (*v); 292121054Semax} 293121054Semax 294121054Semaxstatic __inline void 295124305Semaxatomic_store_32(volatile uint32_t *dst, uint32_t src) 296124305Semax{ 297124305Semax *dst = src; 298121054Semax} 299121054Semax 300121054Semaxstatic __inline uint32_t 301121054Semaxatomic_readandclear_32(volatile u_int32_t *p) 302121054Semax{ 303121054Semax 304121054Semax return (__swp(0, p)); 305121054Semax} 306121054Semax 307121054Semax#undef __with_interrupts_disabled 308124305Semax 309121054Semax#endif /* _LOCORE */ 310121054Semax 311121054Semax 312121054Semaxstatic __inline int 313121054Semaxatomic_cmpset_long(volatile u_long *dst, u_long exp, u_long src) 314124305Semax{ 315124305Semax return (atomic_cmpset_32((volatile u_int *)dst, (u_int)exp, 316124305Semax (u_int)src)); 317121054Semax} 318121054Semax 319121054Semax#define atomic_set_rel_int atomic_set_32 320121054Semax#define atomic_set_acq_long atomic_set_32 321121054Semax#define atomic_set_int atomic_set_32 322124305Semax#define atomic_readandclear_int atomic_readandclear_32 323124305Semax#define atomic_clear_int atomic_clear_32 324124305Semax#define atomic_clear_acq_long atomic_clear_32 325124305Semax#define atomic_subtract_int atomic_subtract_32 326124305Semax#define atomic_subtract_rel_int atomic_subtract_32 327121054Semax#define atomic_subtract_acq_int atomic_subtract_32 328121054Semax#define atomic_add_int atomic_add_32 329121054Semax#define atomic_add_acq_long atomic_add_32 330121054Semax#define atomic_add_rel_int atomic_add_32 331121054Semax#define atomic_add_acq_int atomic_add_32 332124305Semax#define atomic_cmpset_int atomic_cmpset_32 333124305Semax#define atomic_cmpset_rel_int atomic_cmpset_32 334124305Semax#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 335124305Semax#define atomic_cmpset_acq_int atomic_cmpset_32 336124305Semax#define atomic_cmpset_acq_ptr atomic_cmpset_ptr 337124305Semax#define atomic_cmpset_acq_long atomic_cmpset_long 338124305Semax#define atomic_store_rel_ptr atomic_store_ptr 339124305Semax#define atomic_store_rel_int atomic_store_32 340124305Semax#define atomic_cmpset_rel_32 atomic_cmpset_32 341121054Semax#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 342121054Semax#define atomic_load_acq_int atomic_load_32 343121054Semax#define atomic_clear_ptr atomic_clear_32 344121054Semax#define atomic_store_ptr atomic_store_32 345121054Semax#define atomic_cmpset_ptr atomic_cmpset_32 346121054Semax#define atomic_set_ptr atomic_set_32 347124305Semax#define atomic_fetchadd_int atomic_fetchadd_32 348121054Semax 349121054Semax#endif /* _MACHINE_ATOMIC_H_ */ 350121054Semax