aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_gem.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-07-30 15:06:12 -0400
committerDave Airlie <airlied@linux.ie>2008-10-17 17:10:12 -0400
commit673a394b1e3b69be886ff24abfd6df97c52e8d08 (patch)
tree61ca8299333ab50ffc46cf328b20eb25133392ff /drivers/gpu/drm/drm_gem.c
parentd1d8c925b71dd6753bf438f9e14a9e5c5183bcc6 (diff)
drm: Add GEM ("graphics execution manager") to i915 driver.
GEM allows the creation of persistent buffer objects accessible by the graphics device through new ioctls for managing execution of commands on the device. The userland API is almost entirely driver-specific to ensure that any driver building on this model can easily map the interface to individual driver requirements. GEM is used by the 2d driver for managing its internal state allocations and will be used for pixmap storage to reduce memory consumption and enable zero-copy GLX_EXT_texture_from_pixmap, and in the 3d driver is used to enable GL_EXT_framebuffer_object and GL_ARB_pixel_buffer_object. Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_gem.c')
-rw-r--r--drivers/gpu/drm/drm_gem.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
new file mode 100644
index 000000000000..434155b387e9
--- /dev/null
+++ b/drivers/gpu/drm/drm_gem.c
@@ -0,0 +1,420 @@
1/*
2 * Copyright © 2008 Intel Corporation
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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28#include <linux/types.h>
29#include <linux/slab.h>
30#include <linux/mm.h>
31#include <linux/uaccess.h>
32#include <linux/fs.h>
33#include <linux/file.h>
34#include <linux/module.h>
35#include <linux/mman.h>
36#include <linux/pagemap.h>
37#include "drmP.h"
38
39/** @file drm_gem.c
40 *
41 * This file provides some of the base ioctls and library routines for
42 * the graphics memory manager implemented by each device driver.
43 *
44 * Because various devices have different requirements in terms of
45 * synchronization and migration strategies, implementing that is left up to
46 * the driver, and all that the general API provides should be generic --
47 * allocating objects, reading/writing data with the cpu, freeing objects.
48 * Even there, platform-dependent optimizations for reading/writing data with
49 * the CPU mean we'll likely hook those out to driver-specific calls. However,
50 * the DRI2 implementation wants to have at least allocate/mmap be generic.
51 *
52 * The goal was to have swap-backed object allocation managed through
53 * struct file. However, file descriptors as handles to a struct file have
54 * two major failings:
55 * - Process limits prevent more than 1024 or so being used at a time by
56 * default.
57 * - Inability to allocate high fds will aggravate the X Server's select()
58 * handling, and likely that of many GL client applications as well.
59 *
60 * This led to a plan of using our own integer IDs (called handles, following
61 * DRM terminology) to mimic fds, and implement the fd syscalls we need as
62 * ioctls. The objects themselves will still include the struct file so
63 * that we can transition to fds if the required kernel infrastructure shows
64 * up at a later date, and as our interface with shmfs for memory allocation.
65 */
66
67/**
68 * Initialize the GEM device fields
69 */
70
71int
72drm_gem_init(struct drm_device *dev)
73{
74 spin_lock_init(&dev->object_name_lock);
75 idr_init(&dev->object_name_idr);
76 atomic_set(&dev->object_count, 0);
77 atomic_set(&dev->object_memory, 0);
78 atomic_set(&dev->pin_count, 0);
79 atomic_set(&dev->pin_memory, 0);
80 atomic_set(&dev->gtt_count, 0);
81 atomic_set(&dev->gtt_memory, 0);
82 return 0;
83}
84
85/**
86 * Allocate a GEM object of the specified size with shmfs backing store
87 */
88struct drm_gem_object *
89drm_gem_object_alloc(struct drm_device *dev, size_t size)
90{
91 struct drm_gem_object *obj;
92
93 BUG_ON((size & (PAGE_SIZE - 1)) != 0);
94
95 obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
96
97 obj->dev = dev;
98 obj->filp = shmem_file_setup("drm mm object", size, 0);
99 if (IS_ERR(obj->filp)) {
100 kfree(obj);
101 return NULL;
102 }
103
104 kref_init(&obj->refcount);
105 kref_init(&obj->handlecount);
106 obj->size = size;
107 if (dev->driver->gem_init_object != NULL &&
108 dev->driver->gem_init_object(obj) != 0) {
109 fput(obj->filp);
110 kfree(obj);
111 return NULL;
112 }
113 atomic_inc(&dev->object_count);
114 atomic_add(obj->size, &dev->object_memory);
115 return obj;
116}
117EXPORT_SYMBOL(drm_gem_object_alloc);
118
119/**
120 * Removes the mapping from handle to filp for this object.
121 */
122static int
123drm_gem_handle_delete(struct drm_file *filp, int handle)
124{
125 struct drm_device *dev;
126 struct drm_gem_object *obj;
127
128 /* This is gross. The idr system doesn't let us try a delete and
129 * return an error code. It just spews if you fail at deleting.
130 * So, we have to grab a lock around finding the object and then
131 * doing the delete on it and dropping the refcount, or the user
132 * could race us to double-decrement the refcount and cause a
133 * use-after-free later. Given the frequency of our handle lookups,
134 * we may want to use ida for number allocation and a hash table
135 * for the pointers, anyway.
136 */
137 spin_lock(&filp->table_lock);
138
139 /* Check if we currently have a reference on the object */
140 obj = idr_find(&filp->object_idr, handle);
141 if (obj == NULL) {
142 spin_unlock(&filp->table_lock);
143 return -EINVAL;
144 }
145 dev = obj->dev;
146
147 /* Release reference and decrement refcount. */
148 idr_remove(&filp->object_idr, handle);
149 spin_unlock(&filp->table_lock);
150
151 mutex_lock(&dev->struct_mutex);
152 drm_gem_object_handle_unreference(obj);
153 mutex_unlock(&dev->struct_mutex);
154
155 return 0;
156}
157
158/**
159 * Create a handle for this object. This adds a handle reference
160 * to the object, which includes a regular reference count. Callers
161 * will likely want to dereference the object afterwards.
162 */
163int
164drm_gem_handle_create(struct drm_file *file_priv,
165 struct drm_gem_object *obj,
166 int *handlep)
167{
168 int ret;
169
170 /*
171 * Get the user-visible handle using idr.
172 */
173again:
174 /* ensure there is space available to allocate a handle */
175 if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
176 return -ENOMEM;
177
178 /* do the allocation under our spinlock */
179 spin_lock(&file_priv->table_lock);
180 ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
181 spin_unlock(&file_priv->table_lock);
182 if (ret == -EAGAIN)
183 goto again;
184
185 if (ret != 0)
186 return ret;
187
188 drm_gem_object_handle_reference(obj);
189 return 0;
190}
191EXPORT_SYMBOL(drm_gem_handle_create);
192
193/** Returns a reference to the object named by the handle. */
194struct drm_gem_object *
195drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
196 int handle)
197{
198 struct drm_gem_object *obj;
199
200 spin_lock(&filp->table_lock);
201
202 /* Check if we currently have a reference on the object */
203 obj = idr_find(&filp->object_idr, handle);
204 if (obj == NULL) {
205 spin_unlock(&filp->table_lock);
206 return NULL;
207 }
208
209 drm_gem_object_reference(obj);
210
211 spin_unlock(&filp->table_lock);
212
213 return obj;
214}
215EXPORT_SYMBOL(drm_gem_object_lookup);
216
217/**
218 * Releases the handle to an mm object.
219 */
220int
221drm_gem_close_ioctl(struct drm_device *dev, void *data,
222 struct drm_file *file_priv)
223{
224 struct drm_gem_close *args = data;
225 int ret;
226
227 if (!(dev->driver->driver_features & DRIVER_GEM))
228 return -ENODEV;
229
230 ret = drm_gem_handle_delete(file_priv, args->handle);
231
232 return ret;
233}
234
235/**
236 * Create a global name for an object, returning the name.
237 *
238 * Note that the name does not hold a reference; when the object
239 * is freed, the name goes away.
240 */
241int
242drm_gem_flink_ioctl(struct drm_device *dev, void *data,
243 struct drm_file *file_priv)
244{
245 struct drm_gem_flink *args = data;
246 struct drm_gem_object *obj;
247 int ret;
248
249 if (!(dev->driver->driver_features & DRIVER_GEM))
250 return -ENODEV;
251
252 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
253 if (obj == NULL)
254 return -EINVAL;
255
256again:
257 if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
258 return -ENOMEM;
259
260 spin_lock(&dev->object_name_lock);
261 if (obj->name) {
262 spin_unlock(&dev->object_name_lock);
263 return -EEXIST;
264 }
265 ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
266 &obj->name);
267 spin_unlock(&dev->object_name_lock);
268 if (ret == -EAGAIN)
269 goto again;
270
271 if (ret != 0) {
272 mutex_lock(&dev->struct_mutex);
273 drm_gem_object_unreference(obj);
274 mutex_unlock(&dev->struct_mutex);
275 return ret;
276 }
277
278 /*
279 * Leave the reference from the lookup around as the
280 * name table now holds one
281 */
282 args->name = (uint64_t) obj->name;
283
284 return 0;
285}
286
287/**
288 * Open an object using the global name, returning a handle and the size.
289 *
290 * This handle (of course) holds a reference to the object, so the object
291 * will not go away until the handle is deleted.
292 */
293int
294drm_gem_open_ioctl(struct drm_device *dev, void *data,
295 struct drm_file *file_priv)
296{
297 struct drm_gem_open *args = data;
298 struct drm_gem_object *obj;
299 int ret;
300 int handle;
301
302 if (!(dev->driver->driver_features & DRIVER_GEM))
303 return -ENODEV;
304
305 spin_lock(&dev->object_name_lock);
306 obj = idr_find(&dev->object_name_idr, (int) args->name);
307 if (obj)
308 drm_gem_object_reference(obj);
309 spin_unlock(&dev->object_name_lock);
310 if (!obj)
311 return -ENOENT;
312
313 ret = drm_gem_handle_create(file_priv, obj, &handle);
314 mutex_lock(&dev->struct_mutex);
315 drm_gem_object_unreference(obj);
316 mutex_unlock(&dev->struct_mutex);
317 if (ret)
318 return ret;
319
320 args->handle = handle;
321 args->size = obj->size;
322
323 return 0;
324}
325
326/**
327 * Called at device open time, sets up the structure for handling refcounting
328 * of mm objects.
329 */
330void
331drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
332{
333 idr_init(&file_private->object_idr);
334 spin_lock_init(&file_private->table_lock);
335}
336
337/**
338 * Called at device close to release the file's
339 * handle references on objects.
340 */
341static int
342drm_gem_object_release_handle(int id, void *ptr, void *data)
343{
344 struct drm_gem_object *obj = ptr;
345
346 drm_gem_object_handle_unreference(obj);
347
348 return 0;
349}
350
351/**
352 * Called at close time when the filp is going away.
353 *
354 * Releases any remaining references on objects by this filp.
355 */
356void
357drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
358{
359 mutex_lock(&dev->struct_mutex);
360 idr_for_each(&file_private->object_idr,
361 &drm_gem_object_release_handle, NULL);
362
363 idr_destroy(&file_private->object_idr);
364 mutex_unlock(&dev->struct_mutex);
365}
366
367/**
368 * Called after the last reference to the object has been lost.
369 *
370 * Frees the object
371 */
372void
373drm_gem_object_free(struct kref *kref)
374{
375 struct drm_gem_object *obj = (struct drm_gem_object *) kref;
376 struct drm_device *dev = obj->dev;
377
378 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
379
380 if (dev->driver->gem_free_object != NULL)
381 dev->driver->gem_free_object(obj);
382
383 fput(obj->filp);
384 atomic_dec(&dev->object_count);
385 atomic_sub(obj->size, &dev->object_memory);
386 kfree(obj);
387}
388EXPORT_SYMBOL(drm_gem_object_free);
389
390/**
391 * Called after the last handle to the object has been closed
392 *
393 * Removes any name for the object. Note that this must be
394 * called before drm_gem_object_free or we'll be touching
395 * freed memory
396 */
397void
398drm_gem_object_handle_free(struct kref *kref)
399{
400 struct drm_gem_object *obj = container_of(kref,
401 struct drm_gem_object,
402 handlecount);
403 struct drm_device *dev = obj->dev;
404
405 /* Remove any name for this object */
406 spin_lock(&dev->object_name_lock);
407 if (obj->name) {
408 idr_remove(&dev->object_name_idr, obj->name);
409 spin_unlock(&dev->object_name_lock);
410 /*
411 * The object name held a reference to this object, drop
412 * that now.
413 */
414 drm_gem_object_unreference(obj);
415 } else
416 spin_unlock(&dev->object_name_lock);
417
418}
419EXPORT_SYMBOL(drm_gem_object_handle_free);
420