aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_sman.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-28 20:09:59 -0400
committerDave Airlie <airlied@redhat.com>2008-07-13 20:45:01 -0400
commitc0e09200dc0813972442e550a5905a132768e56c (patch)
treed38e635a30ff8b0a2b98b9d7f97cab1501f8209e /drivers/gpu/drm/drm_sman.c
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
drm: reorganise drm tree to be more future proof.
With the coming of kernel based modesetting and the memory manager stuff, the everything in one directory approach was getting very ugly and starting to be unmanageable. This restructures the drm along the lines of other kernel components. It creates a drivers/gpu/drm directory and moves the hw drivers into subdirectores. It moves the includes into an include/drm, and sets up the unifdef for the userspace headers we should be exporting. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_sman.c')
-rw-r--r--drivers/gpu/drm/drm_sman.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_sman.c b/drivers/gpu/drm/drm_sman.c
new file mode 100644
index 000000000000..926f146390ce
--- /dev/null
+++ b/drivers/gpu/drm/drm_sman.c
@@ -0,0 +1,353 @@
1/**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
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 NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28/*
29 * Simple memory manager interface that keeps track on allocate regions on a
30 * per "owner" basis. All regions associated with an "owner" can be released
31 * with a simple call. Typically if the "owner" exists. The owner is any
32 * "unsigned long" identifier. Can typically be a pointer to a file private
33 * struct or a context identifier.
34 *
35 * Authors:
36 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
37 */
38
39#include "drm_sman.h"
40
41struct drm_owner_item {
42 struct drm_hash_item owner_hash;
43 struct list_head sman_list;
44 struct list_head mem_blocks;
45};
46
47void drm_sman_takedown(struct drm_sman * sman)
48{
49 drm_ht_remove(&sman->user_hash_tab);
50 drm_ht_remove(&sman->owner_hash_tab);
51 if (sman->mm)
52 drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
53 DRM_MEM_MM);
54}
55
56EXPORT_SYMBOL(drm_sman_takedown);
57
58int
59drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
60 unsigned int user_order, unsigned int owner_order)
61{
62 int ret = 0;
63
64 sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, sizeof(*sman->mm),
65 DRM_MEM_MM);
66 if (!sman->mm) {
67 ret = -ENOMEM;
68 goto out;
69 }
70 sman->num_managers = num_managers;
71 INIT_LIST_HEAD(&sman->owner_items);
72 ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
73 if (ret)
74 goto out1;
75 ret = drm_ht_create(&sman->user_hash_tab, user_order);
76 if (!ret)
77 goto out;
78
79 drm_ht_remove(&sman->owner_hash_tab);
80out1:
81 drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
82out:
83 return ret;
84}
85
86EXPORT_SYMBOL(drm_sman_init);
87
88static void *drm_sman_mm_allocate(void *private, unsigned long size,
89 unsigned alignment)
90{
91 struct drm_mm *mm = (struct drm_mm *) private;
92 struct drm_mm_node *tmp;
93
94 tmp = drm_mm_search_free(mm, size, alignment, 1);
95 if (!tmp) {
96 return NULL;
97 }
98 tmp = drm_mm_get_block(tmp, size, alignment);
99 return tmp;
100}
101
102static void drm_sman_mm_free(void *private, void *ref)
103{
104 struct drm_mm_node *node = (struct drm_mm_node *) ref;
105
106 drm_mm_put_block(node);
107}
108
109static void drm_sman_mm_destroy(void *private)
110{
111 struct drm_mm *mm = (struct drm_mm *) private;
112 drm_mm_takedown(mm);
113 drm_free(mm, sizeof(*mm), DRM_MEM_MM);
114}
115
116static unsigned long drm_sman_mm_offset(void *private, void *ref)
117{
118 struct drm_mm_node *node = (struct drm_mm_node *) ref;
119 return node->start;
120}
121
122int
123drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
124 unsigned long start, unsigned long size)
125{
126 struct drm_sman_mm *sman_mm;
127 struct drm_mm *mm;
128 int ret;
129
130 BUG_ON(manager >= sman->num_managers);
131
132 sman_mm = &sman->mm[manager];
133 mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
134 if (!mm) {
135 return -ENOMEM;
136 }
137 sman_mm->private = mm;
138 ret = drm_mm_init(mm, start, size);
139
140 if (ret) {
141 drm_free(mm, sizeof(*mm), DRM_MEM_MM);
142 return ret;
143 }
144
145 sman_mm->allocate = drm_sman_mm_allocate;
146 sman_mm->free = drm_sman_mm_free;
147 sman_mm->destroy = drm_sman_mm_destroy;
148 sman_mm->offset = drm_sman_mm_offset;
149
150 return 0;
151}
152
153EXPORT_SYMBOL(drm_sman_set_range);
154
155int
156drm_sman_set_manager(struct drm_sman * sman, unsigned int manager,
157 struct drm_sman_mm * allocator)
158{
159 BUG_ON(manager >= sman->num_managers);
160 sman->mm[manager] = *allocator;
161
162 return 0;
163}
164EXPORT_SYMBOL(drm_sman_set_manager);
165
166static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
167 unsigned long owner)
168{
169 int ret;
170 struct drm_hash_item *owner_hash_item;
171 struct drm_owner_item *owner_item;
172
173 ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
174 if (!ret) {
175 return drm_hash_entry(owner_hash_item, struct drm_owner_item,
176 owner_hash);
177 }
178
179 owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
180 if (!owner_item)
181 goto out;
182
183 INIT_LIST_HEAD(&owner_item->mem_blocks);
184 owner_item->owner_hash.key = owner;
185 if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
186 goto out1;
187
188 list_add_tail(&owner_item->sman_list, &sman->owner_items);
189 return owner_item;
190
191out1:
192 drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
193out:
194 return NULL;
195}
196
197struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager,
198 unsigned long size, unsigned alignment,
199 unsigned long owner)
200{
201 void *tmp;
202 struct drm_sman_mm *sman_mm;
203 struct drm_owner_item *owner_item;
204 struct drm_memblock_item *memblock;
205
206 BUG_ON(manager >= sman->num_managers);
207
208 sman_mm = &sman->mm[manager];
209 tmp = sman_mm->allocate(sman_mm->private, size, alignment);
210
211 if (!tmp) {
212 return NULL;
213 }
214
215 memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
216
217 if (!memblock)
218 goto out;
219
220 memblock->mm_info = tmp;
221 memblock->mm = sman_mm;
222 memblock->sman = sman;
223
224 if (drm_ht_just_insert_please
225 (&sman->user_hash_tab, &memblock->user_hash,
226 (unsigned long)memblock, 32, 0, 0))
227 goto out1;
228
229 owner_item = drm_sman_get_owner_item(sman, owner);
230 if (!owner_item)
231 goto out2;
232
233 list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
234
235 return memblock;
236
237out2:
238 drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
239out1:
240 drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
241out:
242 sman_mm->free(sman_mm->private, tmp);
243
244 return NULL;
245}
246
247EXPORT_SYMBOL(drm_sman_alloc);
248
249static void drm_sman_free(struct drm_memblock_item *item)
250{
251 struct drm_sman *sman = item->sman;
252
253 list_del(&item->owner_list);
254 drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
255 item->mm->free(item->mm->private, item->mm_info);
256 drm_free(item, sizeof(*item), DRM_MEM_MM);
257}
258
259int drm_sman_free_key(struct drm_sman *sman, unsigned int key)
260{
261 struct drm_hash_item *hash_item;
262 struct drm_memblock_item *memblock_item;
263
264 if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
265 return -EINVAL;
266
267 memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item,
268 user_hash);
269 drm_sman_free(memblock_item);
270 return 0;
271}
272
273EXPORT_SYMBOL(drm_sman_free_key);
274
275static void drm_sman_remove_owner(struct drm_sman *sman,
276 struct drm_owner_item *owner_item)
277{
278 list_del(&owner_item->sman_list);
279 drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
280 drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
281}
282
283int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner)
284{
285
286 struct drm_hash_item *hash_item;
287 struct drm_owner_item *owner_item;
288
289 if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
290 return -1;
291 }
292
293 owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
294 if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
295 drm_sman_remove_owner(sman, owner_item);
296 return -1;
297 }
298
299 return 0;
300}
301
302EXPORT_SYMBOL(drm_sman_owner_clean);
303
304static void drm_sman_do_owner_cleanup(struct drm_sman *sman,
305 struct drm_owner_item *owner_item)
306{
307 struct drm_memblock_item *entry, *next;
308
309 list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
310 owner_list) {
311 drm_sman_free(entry);
312 }
313 drm_sman_remove_owner(sman, owner_item);
314}
315
316void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner)
317{
318
319 struct drm_hash_item *hash_item;
320 struct drm_owner_item *owner_item;
321
322 if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
323
324 return;
325 }
326
327 owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
328 drm_sman_do_owner_cleanup(sman, owner_item);
329}
330
331EXPORT_SYMBOL(drm_sman_owner_cleanup);
332
333void drm_sman_cleanup(struct drm_sman *sman)
334{
335 struct drm_owner_item *entry, *next;
336 unsigned int i;
337 struct drm_sman_mm *sman_mm;
338
339 list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
340 drm_sman_do_owner_cleanup(sman, entry);
341 }
342 if (sman->mm) {
343 for (i = 0; i < sman->num_managers; ++i) {
344 sman_mm = &sman->mm[i];
345 if (sman_mm->private) {
346 sman_mm->destroy(sman_mm->private);
347 sman_mm->private = NULL;
348 }
349 }
350 }
351}
352
353EXPORT_SYMBOL(drm_sman_cleanup);