linux/drivers/gpu/drm/drm_gem.c
<<
>>
Prefs
   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 -EBADF;
 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                args->name = obj->name;
 263                spin_unlock(&dev->object_name_lock);
 264                return 0;
 265        }
 266        ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
 267                                 &obj->name);
 268        spin_unlock(&dev->object_name_lock);
 269        if (ret == -EAGAIN)
 270                goto again;
 271
 272        if (ret != 0) {
 273                mutex_lock(&dev->struct_mutex);
 274                drm_gem_object_unreference(obj);
 275                mutex_unlock(&dev->struct_mutex);
 276                return ret;
 277        }
 278
 279        /*
 280         * Leave the reference from the lookup around as the
 281         * name table now holds one
 282         */
 283        args->name = (uint64_t) obj->name;
 284
 285        return 0;
 286}
 287
 288/**
 289 * Open an object using the global name, returning a handle and the size.
 290 *
 291 * This handle (of course) holds a reference to the object, so the object
 292 * will not go away until the handle is deleted.
 293 */
 294int
 295drm_gem_open_ioctl(struct drm_device *dev, void *data,
 296                   struct drm_file *file_priv)
 297{
 298        struct drm_gem_open *args = data;
 299        struct drm_gem_object *obj;
 300        int ret;
 301        int handle;
 302
 303        if (!(dev->driver->driver_features & DRIVER_GEM))
 304                return -ENODEV;
 305
 306        spin_lock(&dev->object_name_lock);
 307        obj = idr_find(&dev->object_name_idr, (int) args->name);
 308        if (obj)
 309                drm_gem_object_reference(obj);
 310        spin_unlock(&dev->object_name_lock);
 311        if (!obj)
 312                return -ENOENT;
 313
 314        ret = drm_gem_handle_create(file_priv, obj, &handle);
 315        mutex_lock(&dev->struct_mutex);
 316        drm_gem_object_unreference(obj);
 317        mutex_unlock(&dev->struct_mutex);
 318        if (ret)
 319                return ret;
 320
 321        args->handle = handle;
 322        args->size = obj->size;
 323
 324        return 0;
 325}
 326
 327/**
 328 * Called at device open time, sets up the structure for handling refcounting
 329 * of mm objects.
 330 */
 331void
 332drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
 333{
 334        idr_init(&file_private->object_idr);
 335        spin_lock_init(&file_private->table_lock);
 336}
 337
 338/**
 339 * Called at device close to release the file's
 340 * handle references on objects.
 341 */
 342static int
 343drm_gem_object_release_handle(int id, void *ptr, void *data)
 344{
 345        struct drm_gem_object *obj = ptr;
 346
 347        drm_gem_object_handle_unreference(obj);
 348
 349        return 0;
 350}
 351
 352/**
 353 * Called at close time when the filp is going away.
 354 *
 355 * Releases any remaining references on objects by this filp.
 356 */
 357void
 358drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 359{
 360        mutex_lock(&dev->struct_mutex);
 361        idr_for_each(&file_private->object_idr,
 362                     &drm_gem_object_release_handle, NULL);
 363
 364        idr_destroy(&file_private->object_idr);
 365        mutex_unlock(&dev->struct_mutex);
 366}
 367
 368/**
 369 * Called after the last reference to the object has been lost.
 370 *
 371 * Frees the object
 372 */
 373void
 374drm_gem_object_free(struct kref *kref)
 375{
 376        struct drm_gem_object *obj = (struct drm_gem_object *) kref;
 377        struct drm_device *dev = obj->dev;
 378
 379        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 380
 381        if (dev->driver->gem_free_object != NULL)
 382                dev->driver->gem_free_object(obj);
 383
 384        fput(obj->filp);
 385        atomic_dec(&dev->object_count);
 386        atomic_sub(obj->size, &dev->object_memory);
 387        kfree(obj);
 388}
 389EXPORT_SYMBOL(drm_gem_object_free);
 390
 391/**
 392 * Called after the last handle to the object has been closed
 393 *
 394 * Removes any name for the object. Note that this must be
 395 * called before drm_gem_object_free or we'll be touching
 396 * freed memory
 397 */
 398void
 399drm_gem_object_handle_free(struct kref *kref)
 400{
 401        struct drm_gem_object *obj = container_of(kref,
 402                                                  struct drm_gem_object,
 403                                                  handlecount);
 404        struct drm_device *dev = obj->dev;
 405
 406        /* Remove any name for this object */
 407        spin_lock(&dev->object_name_lock);
 408        if (obj->name) {
 409                idr_remove(&dev->object_name_idr, obj->name);
 410                spin_unlock(&dev->object_name_lock);
 411                /*
 412                 * The object name held a reference to this object, drop
 413                 * that now.
 414                 */
 415                drm_gem_object_unreference(obj);
 416        } else
 417                spin_unlock(&dev->object_name_lock);
 418
 419}
 420EXPORT_SYMBOL(drm_gem_object_handle_free);
 421
 422
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.