summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c206
1 files changed, 0 insertions, 206 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c b/drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c
deleted file mode 100644
index 5b011d8c..00000000
--- a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_lockless.c
+++ /dev/null
@@ -1,206 +0,0 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/vmalloc.h>
20#include <linux/atomic.h>
21
22#include "gk20a_allocator.h"
23#include "lockless_allocator_priv.h"
24
25static u64 gk20a_lockless_alloc_length(struct gk20a_allocator *a)
26{
27 struct gk20a_lockless_allocator *pa = a->priv;
28
29 return pa->length;
30}
31
32static u64 gk20a_lockless_alloc_base(struct gk20a_allocator *a)
33{
34 struct gk20a_lockless_allocator *pa = a->priv;
35
36 return pa->base;
37}
38
39static int gk20a_lockless_alloc_inited(struct gk20a_allocator *a)
40{
41 struct gk20a_lockless_allocator *pa = a->priv;
42 int inited = pa->inited;
43
44 rmb();
45 return inited;
46}
47
48static u64 gk20a_lockless_alloc_end(struct gk20a_allocator *a)
49{
50 struct gk20a_lockless_allocator *pa = a->priv;
51
52 return pa->base + pa->length;
53}
54
55static u64 gk20a_lockless_alloc(struct gk20a_allocator *a, u64 len)
56{
57 struct gk20a_lockless_allocator *pa = a->priv;
58 int head, new_head, ret;
59 u64 addr = 0;
60
61 if (len != pa->blk_size)
62 return 0;
63
64 head = ACCESS_ONCE(pa->head);
65 while (head >= 0) {
66 new_head = ACCESS_ONCE(pa->next[head]);
67 ret = cmpxchg(&pa->head, head, new_head);
68 if (ret == head) {
69 addr = pa->base + head * pa->blk_size;
70 atomic_inc(&pa->nr_allocs);
71 alloc_dbg(a, "Alloc node # %d @ addr 0x%llx\n", head,
72 addr);
73 break;
74 }
75 head = ACCESS_ONCE(pa->head);
76 }
77 return addr;
78}
79
80static void gk20a_lockless_free(struct gk20a_allocator *a, u64 addr)
81{
82 struct gk20a_lockless_allocator *pa = a->priv;
83 int head, ret;
84 u64 cur_idx, rem;
85
86 cur_idx = addr - pa->base;
87 rem = do_div(cur_idx, pa->blk_size);
88
89 while (1) {
90 head = ACCESS_ONCE(pa->head);
91 ACCESS_ONCE(pa->next[cur_idx]) = head;
92 ret = cmpxchg(&pa->head, head, cur_idx);
93 if (ret == head) {
94 atomic_dec(&pa->nr_allocs);
95 alloc_dbg(a, "Free node # %llu\n", cur_idx);
96 break;
97 }
98 }
99}
100
101static void gk20a_lockless_alloc_destroy(struct gk20a_allocator *a)
102{
103 struct gk20a_lockless_allocator *pa = a->priv;
104
105 gk20a_fini_alloc_debug(a);
106
107 vfree(pa->next);
108 kfree(pa);
109}
110
111static void gk20a_lockless_print_stats(struct gk20a_allocator *a,
112 struct seq_file *s, int lock)
113{
114 struct gk20a_lockless_allocator *pa = a->priv;
115
116 __alloc_pstat(s, a, "Lockless allocator params:\n");
117 __alloc_pstat(s, a, " start = 0x%llx\n", pa->base);
118 __alloc_pstat(s, a, " end = 0x%llx\n", pa->base + pa->length);
119
120 /* Actual stats. */
121 __alloc_pstat(s, a, "Stats:\n");
122 __alloc_pstat(s, a, " Number allocs = %d\n",
123 atomic_read(&pa->nr_allocs));
124 __alloc_pstat(s, a, " Number free = %d\n",
125 pa->nr_nodes - atomic_read(&pa->nr_allocs));
126}
127
128static const struct gk20a_allocator_ops pool_ops = {
129 .alloc = gk20a_lockless_alloc,
130 .free = gk20a_lockless_free,
131
132 .base = gk20a_lockless_alloc_base,
133 .length = gk20a_lockless_alloc_length,
134 .end = gk20a_lockless_alloc_end,
135 .inited = gk20a_lockless_alloc_inited,
136
137 .fini = gk20a_lockless_alloc_destroy,
138
139 .print_stats = gk20a_lockless_print_stats,
140};
141
142int gk20a_lockless_allocator_init(struct gk20a *g, struct gk20a_allocator *__a,
143 const char *name, u64 base, u64 length,
144 u64 blk_size, u64 flags)
145{
146 int i;
147 int err;
148 int nr_nodes;
149 u64 count, rem;
150 struct gk20a_lockless_allocator *a;
151
152 if (!blk_size)
153 return -EINVAL;
154
155 /*
156 * Ensure we have space for atleast one node & there's no overflow.
157 * In order to control memory footprint, we require count < INT_MAX
158 */
159 count = length;
160 rem = do_div(count, blk_size);
161 if (!base || !count || count > INT_MAX)
162 return -EINVAL;
163
164 a = kzalloc(sizeof(struct gk20a_lockless_allocator), GFP_KERNEL);
165 if (!a)
166 return -ENOMEM;
167
168 err = __gk20a_alloc_common_init(__a, name, a, false, &pool_ops);
169 if (err)
170 goto fail;
171
172 a->next = vzalloc(sizeof(*a->next) * count);
173 if (!a->next) {
174 err = -ENOMEM;
175 goto fail;
176 }
177
178 /* chain the elements together to form the initial free list */
179 nr_nodes = (int)count;
180 for (i = 0; i < nr_nodes; i++)
181 a->next[i] = i + 1;
182 a->next[nr_nodes - 1] = -1;
183
184 a->base = base;
185 a->length = length;
186 a->blk_size = blk_size;
187 a->nr_nodes = nr_nodes;
188 a->flags = flags;
189 atomic_set(&a->nr_allocs, 0);
190
191 wmb();
192 a->inited = true;
193
194 gk20a_init_alloc_debug(g, __a);
195 alloc_dbg(__a, "New allocator: type lockless\n");
196 alloc_dbg(__a, " base 0x%llx\n", a->base);
197 alloc_dbg(__a, " nodes %d\n", a->nr_nodes);
198 alloc_dbg(__a, " blk_size 0x%llx\n", a->blk_size);
199 alloc_dbg(__a, " flags 0x%llx\n", a->flags);
200
201 return 0;
202
203fail:
204 kfree(a);
205 return err;
206}