OSDN Git Service

devfreq_boost: Introduce devfreq boost driver
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / include / linux / percpu-rwsem.h
1 #ifndef _LINUX_PERCPU_RWSEM_H
2 #define _LINUX_PERCPU_RWSEM_H
3
4 #include <linux/atomic.h>
5 #include <linux/rwsem.h>
6 #include <linux/percpu.h>
7 #include <linux/wait.h>
8 #include <linux/rcu_sync.h>
9 #include <linux/lockdep.h>
10
11 struct percpu_rw_semaphore {
12         struct rcu_sync         rss;
13         unsigned int __percpu   *read_count;
14         struct rw_semaphore     rw_sem;
15         wait_queue_head_t       writer;
16         int                     readers_block;
17 };
18
19 extern int __percpu_down_read(struct percpu_rw_semaphore *, int);
20 extern void __percpu_up_read(struct percpu_rw_semaphore *);
21
22 static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
23 {
24         might_sleep();
25
26         rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 0, _RET_IP_);
27
28         preempt_disable();
29         /*
30          * We are in an RCU-sched read-side critical section, so the writer
31          * cannot both change sem->state from readers_fast and start checking
32          * counters while we are here. So if we see !sem->state, we know that
33          * the writer won't be checking until we're past the preempt_enable()
34          * and that one the synchronize_sched() is done, the writer will see
35          * anything we did within this RCU-sched read-size critical section.
36          */
37         __this_cpu_inc(*sem->read_count);
38         if (unlikely(!rcu_sync_is_idle(&sem->rss)))
39                 __percpu_down_read(sem, false); /* Unconditional memory barrier */
40         preempt_enable();
41         /*
42          * The barrier() from preempt_enable() prevents the compiler from
43          * bleeding the critical section out.
44          */
45 }
46
47 static inline int percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
48 {
49         int ret = 1;
50
51         preempt_disable();
52         /*
53          * Same as in percpu_down_read().
54          */
55         __this_cpu_inc(*sem->read_count);
56         if (unlikely(!rcu_sync_is_idle(&sem->rss)))
57                 ret = __percpu_down_read(sem, true); /* Unconditional memory barrier */
58         preempt_enable();
59         /*
60          * The barrier() from preempt_enable() prevents the compiler from
61          * bleeding the critical section out.
62          */
63
64         if (ret)
65                 rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 1, _RET_IP_);
66
67         return ret;
68 }
69
70 static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
71 {
72         /*
73          * The barrier() in preempt_disable() prevents the compiler from
74          * bleeding the critical section out.
75          */
76         preempt_disable();
77         /*
78          * Same as in percpu_down_read().
79          */
80         if (likely(rcu_sync_is_idle(&sem->rss)))
81                 __this_cpu_dec(*sem->read_count);
82         else
83                 __percpu_up_read(sem); /* Unconditional memory barrier */
84         preempt_enable();
85
86         rwsem_release(&sem->rw_sem.dep_map, 1, _RET_IP_);
87 }
88
89 extern void percpu_down_write(struct percpu_rw_semaphore *);
90 extern void percpu_up_write(struct percpu_rw_semaphore *);
91
92 extern int __percpu_init_rwsem(struct percpu_rw_semaphore *,
93                                 const char *, struct lock_class_key *);
94
95 extern void percpu_free_rwsem(struct percpu_rw_semaphore *);
96
97 #define percpu_init_rwsem(sem)                                  \
98 ({                                                              \
99         static struct lock_class_key rwsem_key;                 \
100         __percpu_init_rwsem(sem, #sem, &rwsem_key);             \
101 })
102
103 #define percpu_rwsem_is_held(sem) lockdep_is_held(&(sem)->rw_sem)
104
105 static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem,
106                                         bool read, unsigned long ip)
107 {
108         lock_release(&sem->rw_sem.dep_map, 1, ip);
109 #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
110         if (!read)
111                 sem->rw_sem.owner = NULL;
112 #endif
113 }
114
115 static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem,
116                                         bool read, unsigned long ip)
117 {
118         lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);
119 }
120
121 #endif