linux/arch/sh/include/asm/spinlock-llsc.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0
   2 *
   3 * include/asm-sh/spinlock-llsc.h
   4 *
   5 * Copyright (C) 2002, 2003 Paul Mundt
   6 * Copyright (C) 2006, 2007 Akio Idehara
   7 */
   8#ifndef __ASM_SH_SPINLOCK_LLSC_H
   9#define __ASM_SH_SPINLOCK_LLSC_H
  10
  11#include <asm/barrier.h>
  12#include <asm/processor.h>
  13
  14/*
  15 * Your basic SMP spinlocks, allowing only a single CPU anywhere
  16 */
  17
  18#define arch_spin_is_locked(x)          ((x)->lock <= 0)
  19
  20/*
  21 * Simple spin lock operations.  There are two variants, one clears IRQ's
  22 * on the local processor, one does not.
  23 *
  24 * We make no fairness assumptions.  They have a cost.
  25 */
  26static inline void arch_spin_lock(arch_spinlock_t *lock)
  27{
  28        unsigned long tmp;
  29        unsigned long oldval;
  30
  31        __asm__ __volatile__ (
  32                "1:                                             \n\t"
  33                "movli.l        @%2, %0 ! arch_spin_lock        \n\t"
  34                "mov            %0, %1                          \n\t"
  35                "mov            #0, %0                          \n\t"
  36                "movco.l        %0, @%2                         \n\t"
  37                "bf             1b                              \n\t"
  38                "cmp/pl         %1                              \n\t"
  39                "bf             1b                              \n\t"
  40                : "=&z" (tmp), "=&r" (oldval)
  41                : "r" (&lock->lock)
  42                : "t", "memory"
  43        );
  44}
  45
  46static inline void arch_spin_unlock(arch_spinlock_t *lock)
  47{
  48        unsigned long tmp;
  49
  50        /* This could be optimised with ARCH_HAS_MMIOWB */
  51        mmiowb();
  52        __asm__ __volatile__ (
  53                "mov            #1, %0 ! arch_spin_unlock       \n\t"
  54                "mov.l          %0, @%1                         \n\t"
  55                : "=&z" (tmp)
  56                : "r" (&lock->lock)
  57                : "t", "memory"
  58        );
  59}
  60
  61static inline int arch_spin_trylock(arch_spinlock_t *lock)
  62{
  63        unsigned long tmp, oldval;
  64
  65        __asm__ __volatile__ (
  66                "1:                                             \n\t"
  67                "movli.l        @%2, %0 ! arch_spin_trylock     \n\t"
  68                "mov            %0, %1                          \n\t"
  69                "mov            #0, %0                          \n\t"
  70                "movco.l        %0, @%2                         \n\t"
  71                "bf             1b                              \n\t"
  72                "synco                                          \n\t"
  73                : "=&z" (tmp), "=&r" (oldval)
  74                : "r" (&lock->lock)
  75                : "t", "memory"
  76        );
  77
  78        return oldval;
  79}
  80
  81/*
  82 * Read-write spinlocks, allowing multiple readers but only one writer.
  83 *
  84 * NOTE! it is quite common to have readers in interrupts but no interrupt
  85 * writers. For those circumstances we can "mix" irq-safe locks - any writer
  86 * needs to get a irq-safe write-lock, but readers can get non-irqsafe
  87 * read-locks.
  88 */
  89
  90static inline void arch_read_lock(arch_rwlock_t *rw)
  91{
  92        unsigned long tmp;
  93
  94        __asm__ __volatile__ (
  95                "1:                                             \n\t"
  96                "movli.l        @%1, %0 ! arch_read_lock        \n\t"
  97                "cmp/pl         %0                              \n\t"
  98                "bf             1b                              \n\t"
  99                "add            #-1, %0                         \n\t"
 100                "movco.l        %0, @%1                         \n\t"
 101                "bf             1b                              \n\t"
 102                : "=&z" (tmp)
 103                : "r" (&rw->lock)
 104                : "t", "memory"
 105        );
 106}
 107
 108static inline void arch_read_unlock(arch_rwlock_t *rw)
 109{
 110        unsigned long tmp;
 111
 112        __asm__ __volatile__ (
 113                "1:                                             \n\t"
 114                "movli.l        @%1, %0 ! arch_read_unlock      \n\t"
 115                "add            #1, %0                          \n\t"
 116                "movco.l        %0, @%1                         \n\t"
 117                "bf             1b                              \n\t"
 118                : "=&z" (tmp)
 119                : "r" (&rw->lock)
 120                : "t", "memory"
 121        );
 122}
 123
 124static inline void arch_write_lock(arch_rwlock_t *rw)
 125{
 126        unsigned long tmp;
 127
 128        __asm__ __volatile__ (
 129                "1:                                             \n\t"
 130                "movli.l        @%1, %0 ! arch_write_lock       \n\t"
 131                "cmp/hs         %2, %0                          \n\t"
 132                "bf             1b                              \n\t"
 133                "sub            %2, %0                          \n\t"
 134                "movco.l        %0, @%1                         \n\t"
 135                "bf             1b                              \n\t"
 136                : "=&z" (tmp)
 137                : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
 138                : "t", "memory"
 139        );
 140}
 141
 142static inline void arch_write_unlock(arch_rwlock_t *rw)
 143{
 144        __asm__ __volatile__ (
 145                "mov.l          %1, @%0 ! arch_write_unlock     \n\t"
 146                :
 147                : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
 148                : "t", "memory"
 149        );
 150}
 151
 152static inline int arch_read_trylock(arch_rwlock_t *rw)
 153{
 154        unsigned long tmp, oldval;
 155
 156        __asm__ __volatile__ (
 157                "1:                                             \n\t"
 158                "movli.l        @%2, %0 ! arch_read_trylock     \n\t"
 159                "mov            %0, %1                          \n\t"
 160                "cmp/pl         %0                              \n\t"
 161                "bf             2f                              \n\t"
 162                "add            #-1, %0                         \n\t"
 163                "movco.l        %0, @%2                         \n\t"
 164                "bf             1b                              \n\t"
 165                "2:                                             \n\t"
 166                "synco                                          \n\t"
 167                : "=&z" (tmp), "=&r" (oldval)
 168                : "r" (&rw->lock)
 169                : "t", "memory"
 170        );
 171
 172        return (oldval > 0);
 173}
 174
 175static inline int arch_write_trylock(arch_rwlock_t *rw)
 176{
 177        unsigned long tmp, oldval;
 178
 179        __asm__ __volatile__ (
 180                "1:                                             \n\t"
 181                "movli.l        @%2, %0 ! arch_write_trylock    \n\t"
 182                "mov            %0, %1                          \n\t"
 183                "cmp/hs         %3, %0                          \n\t"
 184                "bf             2f                              \n\t"
 185                "sub            %3, %0                          \n\t"
 186                "2:                                             \n\t"
 187                "movco.l        %0, @%2                         \n\t"
 188                "bf             1b                              \n\t"
 189                "synco                                          \n\t"
 190                : "=&z" (tmp), "=&r" (oldval)
 191                : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
 192                : "t", "memory"
 193        );
 194
 195        return (oldval > (RW_LOCK_BIAS - 1));
 196}
 197
 198#endif /* __ASM_SH_SPINLOCK_LLSC_H */
 199