summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/posix/rwsem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/posix/rwsem.c')
-rw-r--r--drivers/gpu/nvgpu/common/posix/rwsem.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/posix/rwsem.c b/drivers/gpu/nvgpu/common/posix/rwsem.c
new file mode 100644
index 00000000..7a696b75
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/posix/rwsem.c
@@ -0,0 +1,117 @@
1/*
2 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bug.h>
24#include <nvgpu/rwsem.h>
25#include <nvgpu/timers.h>
26
27#include <nvgpu/posix/rwsem.h>
28
29void nvgpu_rwsem_init(struct nvgpu_rwsem *rwsem)
30{
31 memset(rwsem, 0, sizeof(*rwsem));
32
33 nvgpu_spinlock_init(&rwsem->lock);
34}
35
36/*
37 * Acquire.
38 */
39void nvgpu_rwsem_down_read(struct nvgpu_rwsem *rwsem)
40{
41 while (true) {
42 nvgpu_spinlock_acquire(&rwsem->lock);
43
44 /*
45 * If there's a writer try again.
46 */
47 if (rwsem->writers < 0) {
48 nvgpu_spinlock_release(&rwsem->lock);
49 nvgpu_msleep(10);
50 continue;
51 }
52
53 /*
54 * Otherwise decrement the read counter and return.
55 */
56 rwsem->readers -= 1;
57 nvgpu_spinlock_release(&rwsem->lock);
58 return;
59 }
60}
61
62/*
63 * Release.
64 */
65void nvgpu_rwsem_up_read(struct nvgpu_rwsem *rwsem)
66{
67 nvgpu_spinlock_acquire(&rwsem->lock);
68 rwsem->readers += 1;
69
70 /*
71 * Can't be any writers if there was a reader. Also can't be
72 * a positive number of readers. The increments are always
73 * downward so if we have a positive number then there is a
74 * balancing bug.
75 */
76 BUG_ON(rwsem->writers < 0);
77 BUG_ON(rwsem->readers > 0);
78
79 nvgpu_spinlock_release(&rwsem->lock);
80}
81
82void nvgpu_rwsem_down_write(struct nvgpu_rwsem *rwsem)
83{
84 while (true) {
85 nvgpu_spinlock_acquire(&rwsem->lock);
86
87 /*
88 * If there's a reader or a writer try again. Note: in this very
89 * simple implementation it's possible for readers to
90 * indefinitely starve writers.
91 */
92 if (rwsem->writers < 0 || rwsem->readers < 0) {
93 nvgpu_spinlock_release(&rwsem->lock);
94 nvgpu_msleep(10);
95 continue;
96 }
97
98 rwsem->writers -= 1;
99 nvgpu_spinlock_release(&rwsem->lock);
100 return;
101 }
102}
103
104void nvgpu_rwsem_up_write(struct nvgpu_rwsem *rwsem)
105{
106 nvgpu_spinlock_acquire(&rwsem->lock);
107 rwsem->writers += 1;
108
109 /*
110 * Writers can't be positive: that would be an unbalanced free. Readers
111 * must be zero - otherwise this writer should never have had access!
112 */
113 BUG_ON(rwsem->writers > 0);
114 BUG_ON(rwsem->readers != 0);
115
116 nvgpu_spinlock_release(&rwsem->lock);
117}