linux/arch/alpha/include/asm/rwsem.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ALPHA_RWSEM_H
   3#define _ALPHA_RWSEM_H
   4
   5/*
   6 * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
   7 * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
   8 */
   9
  10#ifndef _LINUX_RWSEM_H
  11#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  12#endif
  13
  14#ifdef __KERNEL__
  15
  16#include <linux/compiler.h>
  17
  18#define RWSEM_UNLOCKED_VALUE            0x0000000000000000L
  19#define RWSEM_ACTIVE_BIAS               0x0000000000000001L
  20#define RWSEM_ACTIVE_MASK               0x00000000ffffffffL
  21#define RWSEM_WAITING_BIAS              (-0x0000000100000000L)
  22#define RWSEM_ACTIVE_READ_BIAS          RWSEM_ACTIVE_BIAS
  23#define RWSEM_ACTIVE_WRITE_BIAS         (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  24
  25static inline int ___down_read(struct rw_semaphore *sem)
  26{
  27        long oldcount;
  28#ifndef CONFIG_SMP
  29        oldcount = sem->count.counter;
  30        sem->count.counter += RWSEM_ACTIVE_READ_BIAS;
  31#else
  32        long temp;
  33        __asm__ __volatile__(
  34        "1:     ldq_l   %0,%1\n"
  35        "       addq    %0,%3,%2\n"
  36        "       stq_c   %2,%1\n"
  37        "       beq     %2,2f\n"
  38        "       mb\n"
  39        ".subsection 2\n"
  40        "2:     br      1b\n"
  41        ".previous"
  42        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  43        :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
  44#endif
  45        return (oldcount < 0);
  46}
  47
  48static inline void __down_read(struct rw_semaphore *sem)
  49{
  50        if (unlikely(___down_read(sem)))
  51                rwsem_down_read_failed(sem);
  52}
  53
  54static inline int __down_read_killable(struct rw_semaphore *sem)
  55{
  56        if (unlikely(___down_read(sem)))
  57                if (IS_ERR(rwsem_down_read_failed_killable(sem)))
  58                        return -EINTR;
  59
  60        return 0;
  61}
  62
  63/*
  64 * trylock for reading -- returns 1 if successful, 0 if contention
  65 */
  66static inline int __down_read_trylock(struct rw_semaphore *sem)
  67{
  68        long old, new, res;
  69
  70        res = atomic_long_read(&sem->count);
  71        do {
  72                new = res + RWSEM_ACTIVE_READ_BIAS;
  73                if (new <= 0)
  74                        break;
  75                old = res;
  76                res = atomic_long_cmpxchg(&sem->count, old, new);
  77        } while (res != old);
  78        return res >= 0 ? 1 : 0;
  79}
  80
  81static inline long ___down_write(struct rw_semaphore *sem)
  82{
  83        long oldcount;
  84#ifndef CONFIG_SMP
  85        oldcount = sem->count.counter;
  86        sem->count.counter += RWSEM_ACTIVE_WRITE_BIAS;
  87#else
  88        long temp;
  89        __asm__ __volatile__(
  90        "1:     ldq_l   %0,%1\n"
  91        "       addq    %0,%3,%2\n"
  92        "       stq_c   %2,%1\n"
  93        "       beq     %2,2f\n"
  94        "       mb\n"
  95        ".subsection 2\n"
  96        "2:     br      1b\n"
  97        ".previous"
  98        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  99        :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
 100#endif
 101        return oldcount;
 102}
 103
 104static inline void __down_write(struct rw_semaphore *sem)
 105{
 106        if (unlikely(___down_write(sem)))
 107                rwsem_down_write_failed(sem);
 108}
 109
 110static inline int __down_write_killable(struct rw_semaphore *sem)
 111{
 112        if (unlikely(___down_write(sem))) {
 113                if (IS_ERR(rwsem_down_write_failed_killable(sem)))
 114                        return -EINTR;
 115        }
 116
 117        return 0;
 118}
 119
 120/*
 121 * trylock for writing -- returns 1 if successful, 0 if contention
 122 */
 123static inline int __down_write_trylock(struct rw_semaphore *sem)
 124{
 125        long ret = atomic_long_cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
 126                           RWSEM_ACTIVE_WRITE_BIAS);
 127        if (ret == RWSEM_UNLOCKED_VALUE)
 128                return 1;
 129        return 0;
 130}
 131
 132static inline void __up_read(struct rw_semaphore *sem)
 133{
 134        long oldcount;
 135#ifndef CONFIG_SMP
 136        oldcount = sem->count.counter;
 137        sem->count.counter -= RWSEM_ACTIVE_READ_BIAS;
 138#else
 139        long temp;
 140        __asm__ __volatile__(
 141        "       mb\n"
 142        "1:     ldq_l   %0,%1\n"
 143        "       subq    %0,%3,%2\n"
 144        "       stq_c   %2,%1\n"
 145        "       beq     %2,2f\n"
 146        ".subsection 2\n"
 147        "2:     br      1b\n"
 148        ".previous"
 149        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
 150        :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
 151#endif
 152        if (unlikely(oldcount < 0))
 153                if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
 154                        rwsem_wake(sem);
 155}
 156
 157static inline void __up_write(struct rw_semaphore *sem)
 158{
 159        long count;
 160#ifndef CONFIG_SMP
 161        sem->count.counter -= RWSEM_ACTIVE_WRITE_BIAS;
 162        count = sem->count.counter;
 163#else
 164        long temp;
 165        __asm__ __volatile__(
 166        "       mb\n"
 167        "1:     ldq_l   %0,%1\n"
 168        "       subq    %0,%3,%2\n"
 169        "       stq_c   %2,%1\n"
 170        "       beq     %2,2f\n"
 171        "       subq    %0,%3,%0\n"
 172        ".subsection 2\n"
 173        "2:     br      1b\n"
 174        ".previous"
 175        :"=&r" (count), "=m" (sem->count), "=&r" (temp)
 176        :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
 177#endif
 178        if (unlikely(count))
 179                if ((int)count == 0)
 180                        rwsem_wake(sem);
 181}
 182
 183/*
 184 * downgrade write lock to read lock
 185 */
 186static inline void __downgrade_write(struct rw_semaphore *sem)
 187{
 188        long oldcount;
 189#ifndef CONFIG_SMP
 190        oldcount = sem->count.counter;
 191        sem->count.counter -= RWSEM_WAITING_BIAS;
 192#else
 193        long temp;
 194        __asm__ __volatile__(
 195        "1:     ldq_l   %0,%1\n"
 196        "       addq    %0,%3,%2\n"
 197        "       stq_c   %2,%1\n"
 198        "       beq     %2,2f\n"
 199        "       mb\n"
 200        ".subsection 2\n"
 201        "2:     br      1b\n"
 202        ".previous"
 203        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
 204        :"Ir" (-RWSEM_WAITING_BIAS), "m" (sem->count) : "memory");
 205#endif
 206        if (unlikely(oldcount < 0))
 207                rwsem_downgrade_wake(sem);
 208}
 209
 210#endif /* __KERNEL__ */
 211#endif /* _ALPHA_RWSEM_H */
 212