diff options
Diffstat (limited to 'target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h')
-rw-r--r-- | target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h | 353 |
1 files changed, 0 insertions, 353 deletions
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h deleted file mode 100644 index aaf7726020..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * arch/ubicom32/include/asm/atomic.h - * Atomic operations definitions for Ubicom32 architecture. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#ifndef _ASM_UBICOM32_ATOMIC_H -#define _ASM_UBICOM32_ATOMIC_H - -#include <asm/system.h> -#include <asm/ubicom32-common.h> -#include <asm/types.h> - -/* - * Most instructions on the Ubicom32 processor are atomic in that they - * execute in one clock cycle. However, Linux has several operations - * (e.g. compare and swap) which will require more than a single instruction - * to perform. To achieve this, the Ubicom32 processor uses a single - * global bit in a scratchpad register as a critical section lock. All - * atomic operations acquire this lock. - * - * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic - * operations or by the ldsr to avoid disabling a thread performing an atomic - * operation. - * - * Do not attempt to disable interrupts while holding the atomic operations - * lock or you will DEADLOCK the system. - */ - -#define ATOMIC_INIT(i) { (i) } - -/* - * __atomic_add() - * Add i to v and return the result. - */ -static inline void __atomic_add(int i, atomic_t *v) -{ - atomic_t *vt = v; - - __atomic_lock_acquire(); - vt->counter += i; - __atomic_lock_release(); -} - -/* - * __atomic_sub() - * Subtract i from v and return the result. - */ -static inline void __atomic_sub(int i, atomic_t *v) -{ - atomic_t *vt = v; - - __atomic_lock_acquire(); - vt->counter -= i; - __atomic_lock_release(); -} - -/* - * __atomic_add_return() - * Add i to v and return the result. - * - * The implementation here looks rather odd because we appear to be doing - * the addition twice. In fact that's exactly what we're doing but with - * the ubicom32 instruction set we can do the inner load and add with two - * instructions whereas generating both the atomic result and the "ret" - * result requires three instructions. The second add is generally only as - * costly as a move instruction and in cases where we compare the result - * with a constant the compiler can fold two constant values and do a - * single instruction, thus saving an instruction overall! - * - * At the worst we save one instruction inside the atomic lock. - */ -static inline int __atomic_add_return(int i, atomic_t *v) -{ - int ret; - atomic_t *vt = v; - - __atomic_lock_acquire(); - ret = vt->counter; - vt->counter = ret + i; - __atomic_lock_release(); - - return ret + i; -} - -/* - * __atomic_sub_return() - * Subtract i from v and return the result. - * - * The implementation here looks rather odd because we appear to be doing - * the subtraction twice. In fact that's exactly what we're doing but with - * the ubicom32 instruction set we can do the inner load and sub with two - * instructions whereas generating both the atomic result and the "ret" - * result requires three instructions. The second sub is generally only as - * costly as a move instruction and in cases where we compare the result - * with a constant the compiler can fold two constant values and do a - * single instruction, thus saving an instruction overall! - * - * At the worst we save one instruction inside the atomic lock. - */ -static inline int __atomic_sub_return(int i, atomic_t *v) -{ - int ret; - atomic_t *vt = v; - - __atomic_lock_acquire(); - ret = vt->counter; - vt->counter = ret - i; - __atomic_lock_release(); - - return ret - i; -} - -/* - * PUBLIC API FOR ATOMIC! - */ -#define atomic_add(i,v) (__atomic_add( ((int)i),(v))) -#define atomic_sub(i,v) (__atomic_sub( ((int)i),(v))) -#define atomic_inc(v) (__atomic_add( 1,(v))) -#define atomic_dec(v) (__atomic_sub( 1,(v))) -#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v))) -#define atomic_sub_return(i,v) (__atomic_sub_return( ((int)i),(v))) -#define atomic_inc_return(v) (__atomic_add_return( 1,(v))) -#define atomic_dec_return(v) (__atomic_sub_return( 1,(v))) -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) -#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) - -/* - * atomic_read() - * Acquire the atomic lock and read the variable. - */ -static inline int atomic_read(const atomic_t *v) -{ - int ret; - const atomic_t *vt = v; - - __atomic_lock_acquire(); - ret = vt->counter; - __atomic_lock_release(); - - return ret; -} - -/* - * atomic_set() - * Acquire the atomic lock and set the variable. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - atomic_t *vt = v; - - __atomic_lock_acquire(); - vt->counter = i; - __atomic_lock_release(); -} - -/* - * atomic_cmpxchg - * Acquire the atomic lock and exchange if current == old. - */ -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - int prev; - atomic_t *vt = v; - - __atomic_lock_acquire(); - prev = vt->counter; - if (prev == old) { - vt->counter = new; - } - __atomic_lock_release(); - - return prev; -} - -/* - * atomic_xchg() - * Acquire the atomic lock and exchange values. - */ -static inline int atomic_xchg(atomic_t *v, int new) -{ - int prev; - atomic_t *vt = v; - - __atomic_lock_acquire(); - prev = vt->counter; - vt->counter = new; - __atomic_lock_release(); - - return prev; -} - -/* - * atomic_add_unless() - * Acquire the atomic lock and add a unless the value is u. - */ -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - int prev; - atomic_t *vt = v; - - __atomic_lock_acquire(); - prev = vt->counter; - if (prev != u) { - vt->counter += a; - __atomic_lock_release(); - return 1; - } - - __atomic_lock_release(); - return 0; -} - -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) -#include <asm-generic/atomic-long.h> -#else -#include <asm-generic/atomic.h> -#endif - -/* - * The following is not a real function. The compiler should remove the function - * call as long as the user does not pass in a size that __xchg and __cmpxchg - * are not prepared for. If the user does pass in an unknown size, the user - * will get a link time error. - * - * The no return is to prevent a compiler error that can occur when dealing with - * uninitialized variables. Given that the function doesn't exist there is no - * net effect (and if it did it would not return). - */ -extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn)); - -/* - * __xchg() - * Xchange *ptr for x atomically. - * - * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an - * atomic exchange instruction so we use the global atomic_lock. - */ -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) -{ - unsigned long ret; - - __atomic_lock_acquire(); - - switch (size) { - case 1: - ret = *(volatile unsigned char *)ptr; - *(volatile unsigned char *)ptr = x; - break; - - case 2: - ret = *(volatile unsigned short *)ptr; - *(volatile unsigned short *)ptr = x; - break; - - case 4: - ret = *(volatile unsigned int *)ptr; - *(volatile unsigned int *)ptr = x; - break; - - default: - __xchg_called_with_bad_pointer(); - break; - } - __atomic_lock_release(); - return ret; -} - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) - -/* - * __cmpxchg() - * Compare and Xchange *ptr for x atomically. - * - * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an - * atomic exchange instruction so we use the global atomic_lock. - */ -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size) -{ - unsigned long prev; - - __atomic_lock_acquire(); - switch (size) { - case 1: - prev = *(u8 *)ptr; - if (prev == old) { - *(u8 *)ptr = (u8)next; - } - break; - - case 2: - prev = *(u16 *)ptr; - if (prev == old) { - *(u16 *)ptr = (u16)next; - } - break; - - case 4: - prev = *(u32 *)ptr; - if (prev == old) { - *(u32 *)ptr = (u32)next; - } - break; - - default: - __xchg_called_with_bad_pointer(); - break; - } - __atomic_lock_release(); - return prev; -} - -/* - * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make - * them available. - */ -#define cmpxchg_local(ptr, o, n) \ - ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr)))) - -#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr))) - -#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory") -#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory") -#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory") -#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory") - -#endif /* _ASM_UBICOM32_ATOMIC_H */ |