1e172800e5d3162f97d332b3745e3743ce150ec48Will Deacon#ifndef _ASM_GENERIC_RWSEM_H 2e172800e5d3162f97d332b3745e3743ce150ec48Will Deacon#define _ASM_GENERIC_RWSEM_H 3dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 4dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#ifndef _LINUX_RWSEM_H 5dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead." 6dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#endif 7dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 8dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#ifdef __KERNEL__ 9dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 10dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 11e172800e5d3162f97d332b3745e3743ce150ec48Will Deacon * R/W semaphores originally for PPC using the stuff in lib/rwsem.c. 12dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * Adapted largely from include/asm-i386/rwsem.h 13dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * by Paul Mackerras <paulus@samba.org>. 14dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 15dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 16dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 17dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * the semaphore definition 18dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 19e172800e5d3162f97d332b3745e3743ce150ec48Will Deacon#ifdef CONFIG_64BIT 20dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo# define RWSEM_ACTIVE_MASK 0xffffffffL 21dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#else 22dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo# define RWSEM_ACTIVE_MASK 0x0000ffffL 23dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#endif 24dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 25dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#define RWSEM_UNLOCKED_VALUE 0x00000000L 26dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#define RWSEM_ACTIVE_BIAS 0x00000001L 27dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) 28dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS 29dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) 30dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 31dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 32dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * lock for reading 33dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 34dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __down_read(struct rw_semaphore *sem) 35dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 36dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0)) 37dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo rwsem_down_read_failed(sem); 38dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 39dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 40dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline int __down_read_trylock(struct rw_semaphore *sem) 41dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 42dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo long tmp; 43dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 44dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo while ((tmp = sem->count) >= 0) { 45dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (tmp == cmpxchg(&sem->count, tmp, 46dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo tmp + RWSEM_ACTIVE_READ_BIAS)) { 47dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo return 1; 48dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo } 49dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo } 50dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo return 0; 51dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 52dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 53dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 54dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * lock for writing 55dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 56dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __down_write_nested(struct rw_semaphore *sem, int subclass) 57dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 58dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo long tmp; 59dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 60dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS, 61dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo (atomic_long_t *)&sem->count); 62dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) 63dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo rwsem_down_write_failed(sem); 64dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 65dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 66dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __down_write(struct rw_semaphore *sem) 67dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 68dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo __down_write_nested(sem, 0); 69dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 70dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 71dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline int __down_write_trylock(struct rw_semaphore *sem) 72dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 73dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo long tmp; 74dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 75dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, 76dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo RWSEM_ACTIVE_WRITE_BIAS); 77dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo return tmp == RWSEM_UNLOCKED_VALUE; 78dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 79dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 80dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 81dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * unlock after reading 82dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 83dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __up_read(struct rw_semaphore *sem) 84dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 85dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo long tmp; 86dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 87dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo tmp = atomic_long_dec_return((atomic_long_t *)&sem->count); 88dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) 89dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo rwsem_wake(sem); 90dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 91dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 92dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 93dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * unlock after writing 94dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 95dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __up_write(struct rw_semaphore *sem) 96dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 97dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, 98dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo (atomic_long_t *)&sem->count) < 0)) 99dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo rwsem_wake(sem); 100dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 101dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 102dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 103dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * implement atomic add functionality 104dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 105dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) 106dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 107dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo atomic_long_add(delta, (atomic_long_t *)&sem->count); 108dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 109dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 110dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 111dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * downgrade write lock to read lock 112dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 113dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline void __downgrade_write(struct rw_semaphore *sem) 114dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 115dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo long tmp; 116dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 117dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, 118dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo (atomic_long_t *)&sem->count); 119dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo if (tmp < 0) 120dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo rwsem_downgrade_wake(sem); 121dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 122dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 123dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo/* 124dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo * implement exchange and add functionality 125dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo */ 126dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuostatic inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) 127dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo{ 128dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); 129dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo} 130dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo 131dd472da380c3819740d740cfd70b7f8e700e834bRichard Kuo#endif /* __KERNEL__ */ 132e172800e5d3162f97d332b3745e3743ce150ec48Will Deacon#endif /* _ASM_GENERIC_RWSEM_H */ 133