aboutsummaryrefslogtreecommitdiff
path: root/arch/metag/include/asm/spinlock_lnkget.h
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 12:06:09 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 12:06:09 -0800
commit8fd5e7a2d9574b3cac1c9264ad1aed3b613ed6fe (patch)
tree5696f5d31c6c75b71bfc4852fb234b773e266cfe /arch/metag/include/asm/spinlock_lnkget.h
parent529e5fbcd8d3cb48cf824ac8fde91cc80a9e985f (diff)
parentc60ac31542e93499b58dcfc1e3f6550ba5b5728e (diff)
Merge tag 'metag-v3.9-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag
Pull new ImgTec Meta architecture from James Hogan: "This adds core architecture support for Imagination's Meta processor cores, followed by some later miscellaneous arch/metag cleanups and fixes which I kept separate to ease review: - Support for basic Meta 1 (ATP) and Meta 2 (HTP) core architecture - A few fixes all over, particularly for symbol prefixes - A few privilege protection fixes - Several cleanups (setup.c includes, split out a lot of metag_ksyms.c) - Fix some missing exports - Convert hugetlb to use vm_unmapped_area() - Copy device tree to non-init memory - Provide dma_get_sgtable()" * tag 'metag-v3.9-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag: (61 commits) metag: Provide dma_get_sgtable() metag: prom.h: remove declaration of metag_dt_memblock_reserve() metag: copy devicetree to non-init memory metag: cleanup metag_ksyms.c includes metag: move mm/init.c exports out of metag_ksyms.c metag: move usercopy.c exports out of metag_ksyms.c metag: move setup.c exports out of metag_ksyms.c metag: move kick.c exports out of metag_ksyms.c metag: move traps.c exports out of metag_ksyms.c metag: move irq enable out of irqflags.h on SMP genksyms: fix metag symbol prefix on crc symbols metag: hugetlb: convert to vm_unmapped_area() metag: export clear_page and copy_page metag: export metag_code_cache_flush_all metag: protect more non-MMU memory regions metag: make TXPRIVEXT bits explicit metag: kernel/setup.c: sort includes perf: Enable building perf tools for Meta metag: add boot time LNKGET/LNKSET check metag: add __init to metag_cache_probe() ...
Diffstat (limited to 'arch/metag/include/asm/spinlock_lnkget.h')
-rw-r--r--arch/metag/include/asm/spinlock_lnkget.h249
1 files changed, 249 insertions, 0 deletions
diff --git a/arch/metag/include/asm/spinlock_lnkget.h b/arch/metag/include/asm/spinlock_lnkget.h
new file mode 100644
index 000000000000..ad8436feed8d
--- /dev/null
+++ b/arch/metag/include/asm/spinlock_lnkget.h
@@ -0,0 +1,249 @@
+#ifndef __ASM_SPINLOCK_LNKGET_H
+#define __ASM_SPINLOCK_LNKGET_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 arch_spin_is_locked(arch_spinlock_t *lock)
+{
+ int ret;
+
+ asm volatile ("LNKGETD %0, [%1]\n"
+ "TST %0, #1\n"
+ "MOV %0, #1\n"
+ "XORZ %0, %0, %0\n"
+ : "=&d" (ret)
+ : "da" (&lock->lock)
+ : "cc");
+ return ret;
+}
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+ int tmp;
+
+ asm volatile ("1: LNKGETD %0,[%1]\n"
+ " TST %0, #1\n"
+ " ADD %0, %0, #1\n"
+ " LNKSETDZ [%1], %0\n"
+ " BNZ 1b\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " BNZ 1b\n"
+ : "=&d" (tmp)
+ : "da" (&lock->lock)
+ : "cc");
+
+ smp_mb();
+}
+
+/* Returns 0 if failed to acquire lock */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ int tmp;
+
+ asm volatile (" LNKGETD %0,[%1]\n"
+ " TST %0, #1\n"
+ " ADD %0, %0, #1\n"
+ " LNKSETDZ [%1], %0\n"
+ " BNZ 1f\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " MOV %0, #1\n"
+ "1: XORNZ %0, %0, %0\n"
+ : "=&d" (tmp)
+ : "da" (&lock->lock)
+ : "cc");
+
+ smp_mb();
+
+ return tmp;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ smp_mb();
+
+ asm volatile (" SETD [%0], %1\n"
+ :
+ : "da" (&lock->lock), "da" (0)
+ : "memory");
+}
+
+/*
+ * RWLOCKS
+ *
+ *
+ * Write locks are easy - we just set bit 31. When unlocking, we can
+ * just write zero since the lock is exclusively held.
+ */
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ asm volatile ("1: LNKGETD %0,[%1]\n"
+ " CMP %0, #0\n"
+ " ADD %0, %0, %2\n"
+ " LNKSETDZ [%1], %0\n"
+ " BNZ 1b\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " BNZ 1b\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock), "bd" (0x80000000)
+ : "cc");
+
+ smp_mb();
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ asm volatile (" LNKGETD %0,[%1]\n"
+ " CMP %0, #0\n"
+ " ADD %0, %0, %2\n"
+ " LNKSETDZ [%1], %0\n"
+ " BNZ 1f\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " MOV %0,#1\n"
+ "1: XORNZ %0, %0, %0\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock), "bd" (0x80000000)
+ : "cc");
+
+ smp_mb();
+
+ return tmp;
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+ smp_mb();
+
+ asm volatile (" SETD [%0], %1\n"
+ :
+ : "da" (&rw->lock), "da" (0)
+ : "memory");
+}
+
+/* write_can_lock - would write_trylock() succeed? */
+static inline int arch_write_can_lock(arch_rwlock_t *rw)
+{
+ int ret;
+
+ asm volatile ("LNKGETD %0, [%1]\n"
+ "CMP %0, #0\n"
+ "MOV %0, #1\n"
+ "XORNZ %0, %0, %0\n"
+ : "=&d" (ret)
+ : "da" (&rw->lock)
+ : "cc");
+ return ret;
+}
+
+/*
+ * Read locks are a bit more hairy:
+ * - Exclusively load the lock value.
+ * - Increment it.
+ * - Store new lock value if positive, and we still own this location.
+ * If the value is negative, we've already failed.
+ * - If we failed to store the value, we want a negative result.
+ * - If we failed, try again.
+ * Unlocking is similarly hairy. We may have multiple read locks
+ * currently active. However, we know we won't have any write
+ * locks.
+ */
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ asm volatile ("1: LNKGETD %0,[%1]\n"
+ " ADDS %0, %0, #1\n"
+ " LNKSETDPL [%1], %0\n"
+ " BMI 1b\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " BNZ 1b\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock)
+ : "cc");
+
+ smp_mb();
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ smp_mb();
+
+ asm volatile ("1: LNKGETD %0,[%1]\n"
+ " SUB %0, %0, #1\n"
+ " LNKSETD [%1], %0\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " BNZ 1b\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock)
+ : "cc", "memory");
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ asm volatile (" LNKGETD %0,[%1]\n"
+ " ADDS %0, %0, #1\n"
+ " LNKSETDPL [%1], %0\n"
+ " BMI 1f\n"
+ " DEFR %0, TXSTAT\n"
+ " ANDT %0, %0, #HI(0x3f000000)\n"
+ " CMPT %0, #HI(0x02000000)\n"
+ " MOV %0,#1\n"
+ " BZ 2f\n"
+ "1: MOV %0,#0\n"
+ "2:\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock)
+ : "cc");
+
+ smp_mb();
+
+ return tmp;
+}
+
+/* read_can_lock - would read_trylock() succeed? */
+static inline int arch_read_can_lock(arch_rwlock_t *rw)
+{
+ int tmp;
+
+ asm volatile ("LNKGETD %0, [%1]\n"
+ "CMP %0, %2\n"
+ "MOV %0, #1\n"
+ "XORZ %0, %0, %0\n"
+ : "=&d" (tmp)
+ : "da" (&rw->lock), "bd" (0x80000000)
+ : "cc");
+ return tmp;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define arch_spin_relax(lock) cpu_relax()
+#define arch_read_relax(lock) cpu_relax()
+#define arch_write_relax(lock) cpu_relax()
+
+#endif /* __ASM_SPINLOCK_LNKGET_H */