-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add header files to implement Meta hardware thread locks (used by some other atomic operations), atomics, spinlocks, and bitops. There are 2 main types of atomic primitives for metag (in addition to IRQs off on UP): - LOCK instructions provide locking between hardware threads. - LNKGET/LNKSET instructions provide load-linked/store-conditional operations allowing for lighter weight atomics on Meta2 LOCK instructions allow for hardware threads to acquire voluntary or exclusive hardware thread locks: - LOCK0 releases exclusive and voluntary lock from the running hardware thread. - LOCK1 acquires the voluntary hardware lock, blocking until it becomes available. - LOCK2 implies LOCK1, and additionally acquires the exclusive hardware lock, blocking all other hardware threads from executing. Signed-off-by: James Hogan <james.hogan@imgtec.com>
- Loading branch information
James Hogan
committed
Mar 2, 2013
1 parent
9b802d1
commit 6006c0d
Showing
13 changed files
with
1,395 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef __ASM_METAG_ATOMIC_H | ||
#define __ASM_METAG_ATOMIC_H | ||
|
||
#include <linux/compiler.h> | ||
#include <linux/types.h> | ||
#include <asm/cmpxchg.h> | ||
|
||
#if defined(CONFIG_METAG_ATOMICITY_IRQSOFF) | ||
/* The simple UP case. */ | ||
#include <asm-generic/atomic.h> | ||
#else | ||
|
||
#if defined(CONFIG_METAG_ATOMICITY_LOCK1) | ||
#include <asm/atomic_lock1.h> | ||
#else | ||
#include <asm/atomic_lnkget.h> | ||
#endif | ||
|
||
#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) | ||
|
||
#define atomic_dec_return(v) atomic_sub_return(1, (v)) | ||
#define atomic_inc_return(v) atomic_add_return(1, (v)) | ||
|
||
/* | ||
* atomic_inc_and_test - increment and test | ||
* @v: pointer of type atomic_t | ||
* | ||
* Atomically increments @v by 1 | ||
* and returns true if the result is zero, or false for all | ||
* other cases. | ||
*/ | ||
#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) | ||
|
||
#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) | ||
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) | ||
|
||
#define atomic_inc(v) atomic_add(1, (v)) | ||
#define atomic_dec(v) atomic_sub(1, (v)) | ||
|
||
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | ||
|
||
#define smp_mb__before_atomic_dec() barrier() | ||
#define smp_mb__after_atomic_dec() barrier() | ||
#define smp_mb__before_atomic_inc() barrier() | ||
#define smp_mb__after_atomic_inc() barrier() | ||
|
||
#endif | ||
|
||
#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) | ||
|
||
#include <asm-generic/atomic64.h> | ||
|
||
#endif /* __ASM_METAG_ATOMIC_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#ifndef __ASM_METAG_ATOMIC_LNKGET_H | ||
#define __ASM_METAG_ATOMIC_LNKGET_H | ||
|
||
#define ATOMIC_INIT(i) { (i) } | ||
|
||
#define atomic_set(v, i) ((v)->counter = (i)) | ||
|
||
#include <linux/compiler.h> | ||
|
||
#include <asm/barrier.h> | ||
|
||
/* | ||
* None of these asm statements clobber memory as LNKSET writes around | ||
* the cache so the memory it modifies cannot safely be read by any means | ||
* other than these accessors. | ||
*/ | ||
|
||
static inline int atomic_read(const atomic_t *v) | ||
{ | ||
int temp; | ||
|
||
asm volatile ( | ||
"LNKGETD %0, [%1]\n" | ||
: "=da" (temp) | ||
: "da" (&v->counter)); | ||
|
||
return temp; | ||
} | ||
|
||
static inline void atomic_add(int i, atomic_t *v) | ||
{ | ||
int temp; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %0, [%1]\n" | ||
" ADD %0, %0, %2\n" | ||
" LNKSETD [%1], %0\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp) | ||
: "da" (&v->counter), "bd" (i) | ||
: "cc"); | ||
} | ||
|
||
static inline void atomic_sub(int i, atomic_t *v) | ||
{ | ||
int temp; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %0, [%1]\n" | ||
" SUB %0, %0, %2\n" | ||
" LNKSETD [%1], %0\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp) | ||
: "da" (&v->counter), "bd" (i) | ||
: "cc"); | ||
} | ||
|
||
static inline int atomic_add_return(int i, atomic_t *v) | ||
{ | ||
int result, temp; | ||
|
||
smp_mb(); | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" ADD %1, %1, %3\n" | ||
" LNKSETD [%2], %1\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp), "=&da" (result) | ||
: "da" (&v->counter), "bd" (i) | ||
: "cc"); | ||
|
||
smp_mb(); | ||
|
||
return result; | ||
} | ||
|
||
static inline int atomic_sub_return(int i, atomic_t *v) | ||
{ | ||
int result, temp; | ||
|
||
smp_mb(); | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" SUB %1, %1, %3\n" | ||
" LNKSETD [%2], %1\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp), "=&da" (result) | ||
: "da" (&v->counter), "bd" (i) | ||
: "cc"); | ||
|
||
smp_mb(); | ||
|
||
return result; | ||
} | ||
|
||
static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | ||
{ | ||
int temp; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %0, [%1]\n" | ||
" AND %0, %0, %2\n" | ||
" LNKSETD [%1] %0\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp) | ||
: "da" (&v->counter), "bd" (~mask) | ||
: "cc"); | ||
} | ||
|
||
static inline void atomic_set_mask(unsigned int mask, atomic_t *v) | ||
{ | ||
int temp; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %0, [%1]\n" | ||
" OR %0, %0, %2\n" | ||
" LNKSETD [%1], %0\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp) | ||
: "da" (&v->counter), "bd" (mask) | ||
: "cc"); | ||
} | ||
|
||
static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | ||
{ | ||
int result, temp; | ||
|
||
smp_mb(); | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" CMP %1, %3\n" | ||
" LNKSETDEQ [%2], %4\n" | ||
" BNE 2f\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
"2:\n" | ||
: "=&d" (temp), "=&d" (result) | ||
: "da" (&v->counter), "bd" (old), "da" (new) | ||
: "cc"); | ||
|
||
smp_mb(); | ||
|
||
return result; | ||
} | ||
|
||
static inline int atomic_xchg(atomic_t *v, int new) | ||
{ | ||
int temp, old; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" LNKSETD [%2], %3\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
: "=&d" (temp), "=&d" (old) | ||
: "da" (&v->counter), "da" (new) | ||
: "cc"); | ||
|
||
return old; | ||
} | ||
|
||
static inline int __atomic_add_unless(atomic_t *v, int a, int u) | ||
{ | ||
int result, temp; | ||
|
||
smp_mb(); | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" CMP %1, %3\n" | ||
" ADD %0, %1, %4\n" | ||
" LNKSETDNE [%2], %0\n" | ||
" BEQ 2f\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
"2:\n" | ||
: "=&d" (temp), "=&d" (result) | ||
: "da" (&v->counter), "bd" (u), "bd" (a) | ||
: "cc"); | ||
|
||
smp_mb(); | ||
|
||
return result; | ||
} | ||
|
||
static inline int atomic_sub_if_positive(int i, atomic_t *v) | ||
{ | ||
int result, temp; | ||
|
||
asm volatile ( | ||
"1: LNKGETD %1, [%2]\n" | ||
" SUBS %1, %1, %3\n" | ||
" LNKSETDGE [%2], %1\n" | ||
" BLT 2f\n" | ||
" DEFR %0, TXSTAT\n" | ||
" ANDT %0, %0, #HI(0x3f000000)\n" | ||
" CMPT %0, #HI(0x02000000)\n" | ||
" BNZ 1b\n" | ||
"2:\n" | ||
: "=&d" (temp), "=&da" (result) | ||
: "da" (&v->counter), "bd" (i) | ||
: "cc"); | ||
|
||
return result; | ||
} | ||
|
||
#endif /* __ASM_METAG_ATOMIC_LNKGET_H */ |
Oops, something went wrong.