blob: 9e214a41a2ef3a0a8eab35d85c7df733fedb0085 [file] [log] [blame]
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Atomic operations for ARMv7 */
#ifndef __CROS_EC_ATOMIC_H
#define __CROS_EC_ATOMIC_H
#include "common.h"
/**
* Implements atomic arithmetic operations on 32-bit integers.
*
* It used load/store exclusive.
* If you write directly the integer used as an atomic variable,
* you must either clear explicitly the exclusive monitor (using clrex)
* or do it in exception context (which clears the monitor).
*/
#define ATOMIC_OP(asm_op,a,v) do { \
uint32_t reg0, reg1; \
\
__asm__ __volatile__("1: ldrex %0, [%2]\n" \
#asm_op" %0, %0, %3\n" \
" strex %1, %0, [%2]\n" \
" teq %1, #0\n" \
" bne 1b" \
: "=&r" (reg0), "=&r" (reg1) \
: "r" (a), "r" (v) : "cc"); \
} while (0);
static inline void atomic_clear(uint32_t *addr, uint32_t bits)
{
ATOMIC_OP(bic, addr, bits);
}
static inline void atomic_or(uint32_t *addr, uint32_t bits)
{
ATOMIC_OP(orr, addr, bits);
}
static inline void atomic_add(uint32_t *addr, uint32_t value)
{
ATOMIC_OP(add, addr, value);
}
static inline void atomic_sub(uint32_t *addr, uint32_t value)
{
ATOMIC_OP(sub, addr, value);
}
static inline uint32_t atomic_read_clear(uint32_t *addr)
{
uint32_t ret, tmp;
__asm__ __volatile__(" mov %3, #0\n"
"1: ldrex %0, [%2]\n"
" strex %1, %3, [%2]\n"
" teq %1, #0\n"
" bne 1b"
: "=&r" (ret), "=&r" (tmp)
: "r" (addr), "r" (0) : "cc");
return ret;
}
#endif /* __CROS_EC_ATOMIC_H */