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