atomic.h revision 157725
1168404Spjd/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */ 2168404Spjd 3168404Spjd/*- 4168404Spjd * Copyright (C) 2003-2004 Olivier Houchard 5168404Spjd * Copyright (C) 1994-1997 Mark Brinicombe 6168404Spjd * Copyright (C) 1994 Brini 7168404Spjd * All rights reserved. 8168404Spjd * 9168404Spjd * This code is derived from software written for Brini by Mark Brinicombe 10168404Spjd * 11168404Spjd * Redistribution and use in source and binary forms, with or without 12168404Spjd * modification, are permitted provided that the following conditions 13168404Spjd * are met: 14168404Spjd * 1. Redistributions of source code must retain the above copyright 15168404Spjd * notice, this list of conditions and the following disclaimer. 16168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 17168404Spjd * notice, this list of conditions and the following disclaimer in the 18168404Spjd * documentation and/or other materials provided with the distribution. 19168404Spjd * 3. All advertising materials mentioning features or use of this software 20168404Spjd * must display the following acknowledgement: 21168404Spjd * This product includes software developed by Brini. 22219089Spjd * 4. The name of Brini may not be used to endorse or promote products 23264669Sdelphij * derived from this software without specific prior written permission. 24168404Spjd * 25168404Spjd * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 26219089Spjd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27168404Spjd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28168404Spjd * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29168404Spjd * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30168404Spjd * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31168404Spjd * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32168404Spjd * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33168404Spjd * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34168404Spjd * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35219089Spjd * 36168404Spjd * $FreeBSD: head/sys/arm/include/atomic.h 157725 2006-04-13 14:25:28Z cognet $ 37185029Spjd */ 38185029Spjd 39185029Spjd#ifndef _MACHINE_ATOMIC_H_ 40168404Spjd#define _MACHINE_ATOMIC_H_ 41219089Spjd 42168404Spjd 43219089Spjd 44219089Spjd#ifndef _LOCORE 45219089Spjd 46219089Spjd#include <sys/types.h> 47219089Spjd 48219089Spjd#ifndef I32_bit 49219089Spjd#define I32_bit (1 << 7) /* IRQ disable */ 50168404Spjd#endif 51219089Spjd#ifndef F32_bit 52219089Spjd#define F32_bit (1 << 6) /* FIQ disable */ 53219089Spjd#endif 54219089Spjd 55219089Spjd#define __with_interrupts_disabled(expr) \ 56219089Spjd do { \ 57219089Spjd u_int cpsr_save, tmp; \ 58219089Spjd \ 59219089Spjd __asm __volatile( \ 60219089Spjd "mrs %0, cpsr;" \ 61219089Spjd "orr %1, %0, %2;" \ 62219089Spjd "msr cpsr_all, %1;" \ 63219089Spjd : "=r" (cpsr_save), "=r" (tmp) \ 64219089Spjd : "I" (I32_bit | F32_bit) \ 65219089Spjd : "cc" ); \ 66219089Spjd (expr); \ 67219089Spjd __asm __volatile( \ 68219089Spjd "msr cpsr_all, %0" \ 69185029Spjd : /* no output */ \ 70219089Spjd : "r" (cpsr_save) \ 71185029Spjd : "cc" ); \ 72219089Spjd } while(0) 73219089Spjd 74185029Spjd#define ARM_RAS_START 0xe0000004 75219089Spjd#define ARM_RAS_END 0xe0000008 76219089Spjd 77219089Spjdstatic __inline uint32_t 78219089Spjd__swp(uint32_t val, volatile uint32_t *ptr) 79219089Spjd{ 80219089Spjd __asm __volatile("swp %0, %2, [%3]" 81219089Spjd : "=&r" (val), "=m" (*ptr) 82185029Spjd : "r" (val), "r" (ptr), "m" (*ptr) 83219089Spjd : "memory"); 84219089Spjd return (val); 85219089Spjd} 86219089Spjd 87219089Spjd 88219089Spjd#ifdef _KERNEL 89219089Spjdstatic __inline void 90219089Spjdatomic_set_32(volatile uint32_t *address, uint32_t setmask) 91219089Spjd{ 92219089Spjd __with_interrupts_disabled(*address |= setmask); 93219089Spjd} 94219089Spjd 95219089Spjdstatic __inline void 96219089Spjdatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 97219089Spjd{ 98219089Spjd __with_interrupts_disabled(*address &= ~clearmask); 99219089Spjd} 100219089Spjd 101219089Spjdstatic __inline u_int32_t 102219089Spjdatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 103219089Spjd{ 104219089Spjd int ret; 105219089Spjd 106219089Spjd __with_interrupts_disabled( 107219089Spjd { 108219089Spjd if (*p == cmpval) { 109219089Spjd *p = newval; 110219089Spjd ret = 1; 111219089Spjd } else { 112219089Spjd ret = 0; 113219089Spjd } 114219089Spjd }); 115219089Spjd return (ret); 116219089Spjd} 117185029Spjd 118185029Spjdstatic __inline void 119219089Spjdatomic_add_32(volatile u_int32_t *p, u_int32_t val) 120219089Spjd{ 121219089Spjd __with_interrupts_disabled(*p += val); 122185029Spjd} 123185029Spjd 124219089Spjdstatic __inline void 125185029Spjdatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 126219089Spjd{ 127185029Spjd __with_interrupts_disabled(*p -= val); 128185029Spjd} 129185029Spjd 130185029Spjdstatic __inline uint32_t 131185029Spjdatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 132185029Spjd{ 133185029Spjd uint32_t value; 134185029Spjd 135219089Spjd __with_interrupts_disabled( 136219089Spjd { 137185029Spjd value = *p; 138185029Spjd *p += v; 139185029Spjd }); 140185029Spjd return (value); 141185029Spjd} 142219089Spjd 143219089Spjd#else /* !_KERNEL */ 144185029Spjd 145185029Spjdstatic __inline u_int32_t 146185029Spjdatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 147185029Spjd{ 148185029Spjd register int done, ras_start; 149185029Spjd 150185029Spjd __asm __volatile("1:\n" 151219089Spjd "mov %0, #0xe0000008\n" 152219089Spjd "adr %1, 2f\n" 153185029Spjd "str %1, [%0]\n" 154185029Spjd "adr %1, 1b\n" 155185029Spjd "mov %0, #0xe0000004\n" 156185029Spjd "str %1, [%0]\n" 157185029Spjd "ldr %1, [%2]\n" 158185029Spjd "cmp %1, %3\n" 159219089Spjd "streq %4, [%2]\n" 160185029Spjd "2:\n" 161185029Spjd "mov %1, #0\n" 162219089Spjd "str %1, [%0]\n" 163185029Spjd "moveq %1, #1\n" 164185029Spjd "movne %1, #0\n" 165185029Spjd : "=r" (ras_start), "=r" (done) 166185029Spjd ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory"); 167185029Spjd return (done); 168185029Spjd} 169185029Spjd 170185029Spjdstatic __inline void 171185029Spjdatomic_add_32(volatile u_int32_t *p, u_int32_t val) 172185029Spjd{ 173219089Spjd int ras_start, start; 174185029Spjd 175185029Spjd __asm __volatile("1:\n" 176185029Spjd "mov %0, #0xe0000008\n" 177185029Spjd "adr %1, 2f\n" 178219089Spjd "str %1, [%0]\n" 179219089Spjd "adr %1, 1b\n" 180219089Spjd "mov %0, #0xe0000004\n" 181185029Spjd "str %1, [%0]\n" 182185029Spjd "ldr %1, [%2]\n" 183219089Spjd "add %1, %1, %3\n" 184185029Spjd "str %1, [%2]\n" 185185029Spjd "2:\n" 186185029Spjd "mov %1, #0\n" 187219089Spjd "str %1, [%0]\n" 188219089Spjd : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 189185029Spjd : : "memory"); 190185029Spjd} 191185029Spjd 192185029Spjdstatic __inline void 193185029Spjdatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 194219089Spjd{ 195219089Spjd int ras_start, start; 196185029Spjd 197185029Spjd __asm __volatile("1:\n" 198219089Spjd "mov %0, #0xe0000008\n" 199185029Spjd "adr %1, 2f\n" 200185029Spjd "str %1, [%0]\n" 201185029Spjd "adr %1, 1b\n" 202219089Spjd "mov %0, #0xe0000004\n" 203219089Spjd "str %1, [%0]\n" 204219089Spjd "ldr %1, [%2]\n" 205219089Spjd "sub %1, %1, %3\n" 206219089Spjd "str %1, [%2]\n" 207219089Spjd "2:\n" 208219089Spjd "mov %1, #0\n" 209219089Spjd "str %1, [%0]\n" 210219089Spjd 211219089Spjd : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 212219089Spjd : : "memory"); 213219089Spjd} 214219089Spjd 215219089Spjdstatic __inline void 216219089Spjdatomic_set_32(volatile uint32_t *address, uint32_t setmask) 217219089Spjd{ 218168404Spjd int ras_start, start; 219168404Spjd 220168404Spjd __asm __volatile("1:\n" 221168404Spjd "mov %0, #0xe0000008\n" 222168404Spjd "adr %1, 2f\n" 223168404Spjd "str %1, [%0]\n" 224185029Spjd "adr %1, 1b\n" 225168404Spjd "mov %0, #0xe0000004\n" 226168404Spjd "str %1, [%0]\n" 227168404Spjd "ldr %1, [%2]\n" 228168404Spjd "orr %1, %1, %3\n" 229168404Spjd "str %1, [%2]\n" 230168404Spjd "2:\n" 231168404Spjd "mov %1, #0\n" 232168404Spjd "str %1, [%0]\n" 233168404Spjd 234168404Spjd : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask) 235168404Spjd : : "memory"); 236168404Spjd} 237168404Spjd 238168404Spjdstatic __inline void 239168404Spjdatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 240168404Spjd{ 241168404Spjd int ras_start, start; 242168404Spjd 243168404Spjd __asm __volatile("1:\n" 244168404Spjd "mov %0, #0xe0000008\n" 245168404Spjd "adr %1, 2f\n" 246168404Spjd "str %1, [%0]\n" 247168404Spjd "adr %1, 1b\n" 248168404Spjd "mov %0, #0xe0000004\n" 249168404Spjd "str %1, [%0]\n" 250168404Spjd "ldr %1, [%2]\n" 251168404Spjd "bic %1, %1, %3\n" 252168404Spjd "str %1, [%2]\n" 253168404Spjd "2:\n" 254168404Spjd "mov %1, #0\n" 255168404Spjd "str %1, [%0]\n" 256168404Spjd : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask) 257168404Spjd : : "memory"); 258168404Spjd 259219089Spjd} 260168404Spjd 261219089Spjdstatic __inline uint32_t 262168404Spjdatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 263168404Spjd{ 264168404Spjd uint32_t ras_start, start; 265168404Spjd 266197150Spjd __asm __volatile("1:\n" 267219089Spjd "mov %0, #0xe0000008\n" 268168404Spjd "adr %1, 2f\n" 269168404Spjd "str %1, [%0]\n" 270197150Spjd "adr %1, 1b\n" 271168404Spjd "mov %0, #0xe0000004\n" 272168404Spjd "str %1, [%0]\n" 273168404Spjd "ldr %1, [%2]\n" 274168404Spjd "add %3, %1, %3\n" 275168404Spjd "str %3, [%2]\n" 276168404Spjd "2:\n" 277168404Spjd "mov %3, #0\n" 278219089Spjd "str %3, [%0]\n" 279219089Spjd : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (v) 280197150Spjd : : "memory"); 281197150Spjd return (start); 282197150Spjd} 283197150Spjd 284197150Spjd 285197150Spjd#endif /* _KERNEL */ 286168404Spjd 287168404Spjdstatic __inline int 288168404Spjdatomic_load_32(volatile uint32_t *v) 289185029Spjd{ 290168404Spjd 291168404Spjd return (*v); 292168404Spjd} 293168404Spjd 294185029Spjdstatic __inline void 295168404Spjdatomic_store_32(volatile uint32_t *dst, uint32_t src) 296185029Spjd{ 297185029Spjd *dst = src; 298168404Spjd} 299185029Spjd 300219089Spjdstatic __inline uint32_t 301168404Spjdatomic_readandclear_32(volatile u_int32_t *p) 302185029Spjd{ 303168404Spjd 304168404Spjd return (__swp(0, p)); 305168404Spjd} 306185029Spjd 307219089Spjd#undef __with_interrupts_disabled 308219089Spjd 309168404Spjd#endif /* _LOCORE */ 310168404Spjd 311185029Spjd 312185029Spjdstatic __inline int 313185029Spjdatomic_cmpset_long(volatile u_long *dst, u_long exp, u_long src) 314185029Spjd{ 315168404Spjd return (atomic_cmpset_32((volatile u_int *)dst, (u_int)exp, 316168404Spjd (u_int)src)); 317168404Spjd} 318168404Spjd 319168404Spjd#define atomic_set_rel_int atomic_set_32 320168404Spjd#define atomic_set_acq_long atomic_set_32 321168404Spjd#define atomic_set_int atomic_set_32 322168404Spjd#define atomic_readandclear_int atomic_readandclear_32 323168404Spjd#define atomic_clear_int atomic_clear_32 324168404Spjd#define atomic_clear_acq_long atomic_clear_32 325168404Spjd#define atomic_subtract_int atomic_subtract_32 326168404Spjd#define atomic_subtract_rel_int atomic_subtract_32 327168404Spjd#define atomic_subtract_acq_int atomic_subtract_32 328168404Spjd#define atomic_add_int atomic_add_32 329168404Spjd#define atomic_add_acq_long atomic_add_32 330168404Spjd#define atomic_add_rel_int atomic_add_32 331219089Spjd#define atomic_add_acq_int atomic_add_32 332168404Spjd#define atomic_cmpset_int atomic_cmpset_32 333168404Spjd#define atomic_cmpset_rel_int atomic_cmpset_32 334168404Spjd#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 335168404Spjd#define atomic_cmpset_acq_int atomic_cmpset_32 336219089Spjd#define atomic_cmpset_acq_ptr atomic_cmpset_ptr 337168404Spjd#define atomic_cmpset_acq_long atomic_cmpset_long 338168404Spjd#define atomic_store_rel_ptr atomic_store_ptr 339168404Spjd#define atomic_store_rel_int atomic_store_32 340168404Spjd#define atomic_cmpset_rel_32 atomic_cmpset_32 341168404Spjd#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 342168404Spjd#define atomic_load_acq_int atomic_load_32 343168404Spjd#define atomic_clear_ptr atomic_clear_32 344168404Spjd#define atomic_store_ptr atomic_store_32 345168404Spjd#define atomic_cmpset_ptr atomic_cmpset_32 346168404Spjd#define atomic_set_ptr atomic_set_32 347168404Spjd#define atomic_fetchadd_int atomic_fetchadd_32 348168404Spjd 349168404Spjd#endif /* _MACHINE_ATOMIC_H_ */ 350168404Spjd