1673a394bSEric Anholt /* 2673a394bSEric Anholt * Copyright © 2008 Intel Corporation 3673a394bSEric Anholt * 4673a394bSEric Anholt * Permission is hereby granted, free of charge, to any person obtaining a 5673a394bSEric Anholt * copy of this software and associated documentation files (the "Software"), 6673a394bSEric Anholt * to deal in the Software without restriction, including without limitation 7673a394bSEric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8673a394bSEric Anholt * and/or sell copies of the Software, and to permit persons to whom the 9673a394bSEric Anholt * Software is furnished to do so, subject to the following conditions: 10673a394bSEric Anholt * 11673a394bSEric Anholt * The above copyright notice and this permission notice (including the next 12673a394bSEric Anholt * paragraph) shall be included in all copies or substantial portions of the 13673a394bSEric Anholt * Software. 14673a394bSEric Anholt * 15673a394bSEric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16673a394bSEric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17673a394bSEric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18673a394bSEric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19673a394bSEric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20673a394bSEric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21673a394bSEric Anholt * IN THE SOFTWARE. 22673a394bSEric Anholt * 23673a394bSEric Anholt * Authors: 24673a394bSEric Anholt * Eric Anholt <eric@anholt.net> 25673a394bSEric Anholt * 26673a394bSEric Anholt */ 27673a394bSEric Anholt 28673a394bSEric Anholt #include <linux/types.h> 29673a394bSEric Anholt #include <linux/slab.h> 30673a394bSEric Anholt #include <linux/mm.h> 31673a394bSEric Anholt #include <linux/uaccess.h> 32673a394bSEric Anholt #include <linux/fs.h> 33673a394bSEric Anholt #include <linux/file.h> 34673a394bSEric Anholt #include <linux/module.h> 35673a394bSEric Anholt #include <linux/mman.h> 36673a394bSEric Anholt #include <linux/pagemap.h> 37673a394bSEric Anholt #include "drmP.h" 38673a394bSEric Anholt 39673a394bSEric Anholt /** @file drm_gem.c 40673a394bSEric Anholt * 41673a394bSEric Anholt * This file provides some of the base ioctls and library routines for 42673a394bSEric Anholt * the graphics memory manager implemented by each device driver. 43673a394bSEric Anholt * 44673a394bSEric Anholt * Because various devices have different requirements in terms of 45673a394bSEric Anholt * synchronization and migration strategies, implementing that is left up to 46673a394bSEric Anholt * the driver, and all that the general API provides should be generic -- 47673a394bSEric Anholt * allocating objects, reading/writing data with the cpu, freeing objects. 48673a394bSEric Anholt * Even there, platform-dependent optimizations for reading/writing data with 49673a394bSEric Anholt * the CPU mean we'll likely hook those out to driver-specific calls. However, 50673a394bSEric Anholt * the DRI2 implementation wants to have at least allocate/mmap be generic. 51673a394bSEric Anholt * 52673a394bSEric Anholt * The goal was to have swap-backed object allocation managed through 53673a394bSEric Anholt * struct file. However, file descriptors as handles to a struct file have 54673a394bSEric Anholt * two major failings: 55673a394bSEric Anholt * - Process limits prevent more than 1024 or so being used at a time by 56673a394bSEric Anholt * default. 57673a394bSEric Anholt * - Inability to allocate high fds will aggravate the X Server's select() 58673a394bSEric Anholt * handling, and likely that of many GL client applications as well. 59673a394bSEric Anholt * 60673a394bSEric Anholt * This led to a plan of using our own integer IDs (called handles, following 61673a394bSEric Anholt * DRM terminology) to mimic fds, and implement the fd syscalls we need as 62673a394bSEric Anholt * ioctls. The objects themselves will still include the struct file so 63673a394bSEric Anholt * that we can transition to fds if the required kernel infrastructure shows 64673a394bSEric Anholt * up at a later date, and as our interface with shmfs for memory allocation. 65673a394bSEric Anholt */ 66673a394bSEric Anholt 67673a394bSEric Anholt /** 68673a394bSEric Anholt * Initialize the GEM device fields 69673a394bSEric Anholt */ 70673a394bSEric Anholt 71673a394bSEric Anholt int 72673a394bSEric Anholt drm_gem_init(struct drm_device *dev) 73673a394bSEric Anholt { 74673a394bSEric Anholt spin_lock_init(&dev->object_name_lock); 75673a394bSEric Anholt idr_init(&dev->object_name_idr); 76673a394bSEric Anholt atomic_set(&dev->object_count, 0); 77673a394bSEric Anholt atomic_set(&dev->object_memory, 0); 78673a394bSEric Anholt atomic_set(&dev->pin_count, 0); 79673a394bSEric Anholt atomic_set(&dev->pin_memory, 0); 80673a394bSEric Anholt atomic_set(&dev->gtt_count, 0); 81673a394bSEric Anholt atomic_set(&dev->gtt_memory, 0); 82673a394bSEric Anholt return 0; 83673a394bSEric Anholt } 84673a394bSEric Anholt 85673a394bSEric Anholt /** 86673a394bSEric Anholt * Allocate a GEM object of the specified size with shmfs backing store 87673a394bSEric Anholt */ 88673a394bSEric Anholt struct drm_gem_object * 89673a394bSEric Anholt drm_gem_object_alloc(struct drm_device *dev, size_t size) 90673a394bSEric Anholt { 91673a394bSEric Anholt struct drm_gem_object *obj; 92673a394bSEric Anholt 93673a394bSEric Anholt BUG_ON((size & (PAGE_SIZE - 1)) != 0); 94673a394bSEric Anholt 95673a394bSEric Anholt obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); 96673a394bSEric Anholt 97673a394bSEric Anholt obj->dev = dev; 98673a394bSEric Anholt obj->filp = shmem_file_setup("drm mm object", size, 0); 99673a394bSEric Anholt if (IS_ERR(obj->filp)) { 100673a394bSEric Anholt kfree(obj); 101673a394bSEric Anholt return NULL; 102673a394bSEric Anholt } 103673a394bSEric Anholt 104673a394bSEric Anholt kref_init(&obj->refcount); 105673a394bSEric Anholt kref_init(&obj->handlecount); 106673a394bSEric Anholt obj->size = size; 107673a394bSEric Anholt if (dev->driver->gem_init_object != NULL && 108673a394bSEric Anholt dev->driver->gem_init_object(obj) != 0) { 109673a394bSEric Anholt fput(obj->filp); 110673a394bSEric Anholt kfree(obj); 111673a394bSEric Anholt return NULL; 112673a394bSEric Anholt } 113673a394bSEric Anholt atomic_inc(&dev->object_count); 114673a394bSEric Anholt atomic_add(obj->size, &dev->object_memory); 115673a394bSEric Anholt return obj; 116673a394bSEric Anholt } 117673a394bSEric Anholt EXPORT_SYMBOL(drm_gem_object_alloc); 118673a394bSEric Anholt 119673a394bSEric Anholt /** 120673a394bSEric Anholt * Removes the mapping from handle to filp for this object. 121673a394bSEric Anholt */ 122673a394bSEric Anholt static int 123673a394bSEric Anholt drm_gem_handle_delete(struct drm_file *filp, int handle) 124673a394bSEric Anholt { 125673a394bSEric Anholt struct drm_device *dev; 126673a394bSEric Anholt struct drm_gem_object *obj; 127673a394bSEric Anholt 128673a394bSEric Anholt /* This is gross. The idr system doesn't let us try a delete and 129673a394bSEric Anholt * return an error code. It just spews if you fail at deleting. 130673a394bSEric Anholt * So, we have to grab a lock around finding the object and then 131673a394bSEric Anholt * doing the delete on it and dropping the refcount, or the user 132673a394bSEric Anholt * could race us to double-decrement the refcount and cause a 133673a394bSEric Anholt * use-after-free later. Given the frequency of our handle lookups, 134673a394bSEric Anholt * we may want to use ida for number allocation and a hash table 135673a394bSEric Anholt * for the pointers, anyway. 136673a394bSEric Anholt */ 137673a394bSEric Anholt spin_lock(&filp->table_lock); 138673a394bSEric Anholt 139673a394bSEric Anholt /* Check if we currently have a reference on the object */ 140673a394bSEric Anholt obj = idr_find(&filp->object_idr, handle); 141673a394bSEric Anholt if (obj == NULL) { 142673a394bSEric Anholt spin_unlock(&filp->table_lock); 143673a394bSEric Anholt return -EINVAL; 144673a394bSEric Anholt } 145673a394bSEric Anholt dev = obj->dev; 146673a394bSEric Anholt 147673a394bSEric Anholt /* Release reference and decrement refcount. */ 148673a394bSEric Anholt idr_remove(&filp->object_idr, handle); 149673a394bSEric Anholt spin_unlock(&filp->table_lock); 150673a394bSEric Anholt 151673a394bSEric Anholt mutex_lock(&dev->struct_mutex); 152673a394bSEric Anholt drm_gem_object_handle_unreference(obj); 153673a394bSEric Anholt mutex_unlock(&dev->struct_mutex); 154673a394bSEric Anholt 155673a394bSEric Anholt return 0; 156673a394bSEric Anholt } 157673a394bSEric Anholt 158673a394bSEric Anholt /** 159673a394bSEric Anholt * Create a handle for this object. This adds a handle reference 160673a394bSEric Anholt * to the object, which includes a regular reference count. Callers 161673a394bSEric Anholt * will likely want to dereference the object afterwards. 162673a394bSEric Anholt */ 163673a394bSEric Anholt int 164673a394bSEric Anholt drm_gem_handle_create(struct drm_file *file_priv, 165673a394bSEric Anholt struct drm_gem_object *obj, 166673a394bSEric Anholt int *handlep) 167673a394bSEric Anholt { 168673a394bSEric Anholt int ret; 169673a394bSEric Anholt 170673a394bSEric Anholt /* 171673a394bSEric Anholt * Get the user-visible handle using idr. 172673a394bSEric Anholt */ 173673a394bSEric Anholt again: 174673a394bSEric Anholt /* ensure there is space available to allocate a handle */ 175673a394bSEric Anholt if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) 176673a394bSEric Anholt return -ENOMEM; 177673a394bSEric Anholt 178673a394bSEric Anholt /* do the allocation under our spinlock */ 179673a394bSEric Anholt spin_lock(&file_priv->table_lock); 180673a394bSEric Anholt ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); 181673a394bSEric Anholt spin_unlock(&file_priv->table_lock); 182673a394bSEric Anholt if (ret == -EAGAIN) 183673a394bSEric Anholt goto again; 184673a394bSEric Anholt 185673a394bSEric Anholt if (ret != 0) 186673a394bSEric Anholt return ret; 187673a394bSEric Anholt 188673a394bSEric Anholt drm_gem_object_handle_reference(obj); 189673a394bSEric Anholt return 0; 190673a394bSEric Anholt } 191673a394bSEric Anholt EXPORT_SYMBOL(drm_gem_handle_create); 192673a394bSEric Anholt 193673a394bSEric Anholt /** Returns a reference to the object named by the handle. */ 194673a394bSEric Anholt struct drm_gem_object * 195673a394bSEric Anholt drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, 196673a394bSEric Anholt int handle) 197673a394bSEric Anholt { 198673a394bSEric Anholt struct drm_gem_object *obj; 199673a394bSEric Anholt 200673a394bSEric Anholt spin_lock(&filp->table_lock); 201673a394bSEric Anholt 202673a394bSEric Anholt /* Check if we currently have a reference on the object */ 203673a394bSEric Anholt obj = idr_find(&filp->object_idr, handle); 204673a394bSEric Anholt if (obj == NULL) { 205673a394bSEric Anholt spin_unlock(&filp->table_lock); 206673a394bSEric Anholt return NULL; 207673a394bSEric Anholt } 208673a394bSEric Anholt 209673a394bSEric Anholt drm_gem_object_reference(obj); 210673a394bSEric Anholt 211673a394bSEric Anholt spin_unlock(&filp->table_lock); 212673a394bSEric Anholt 213673a394bSEric Anholt return obj; 214673a394bSEric Anholt } 215673a394bSEric Anholt EXPORT_SYMBOL(drm_gem_object_lookup); 216673a394bSEric Anholt 217673a394bSEric Anholt /** 218673a394bSEric Anholt * Releases the handle to an mm object. 219673a394bSEric Anholt */ 220673a394bSEric Anholt int 221673a394bSEric Anholt drm_gem_close_ioctl(struct drm_device *dev, void *data, 222673a394bSEric Anholt struct drm_file *file_priv) 223673a394bSEric Anholt { 224673a394bSEric Anholt struct drm_gem_close *args = data; 225673a394bSEric Anholt int ret; 226673a394bSEric Anholt 227673a394bSEric Anholt if (!(dev->driver->driver_features & DRIVER_GEM)) 228673a394bSEric Anholt return -ENODEV; 229673a394bSEric Anholt 230673a394bSEric Anholt ret = drm_gem_handle_delete(file_priv, args->handle); 231673a394bSEric Anholt 232673a394bSEric Anholt return ret; 233673a394bSEric Anholt } 234673a394bSEric Anholt 235673a394bSEric Anholt /** 236673a394bSEric Anholt * Create a global name for an object, returning the name. 237673a394bSEric Anholt * 238673a394bSEric Anholt * Note that the name does not hold a reference; when the object 239673a394bSEric Anholt * is freed, the name goes away. 240673a394bSEric Anholt */ 241673a394bSEric Anholt int 242673a394bSEric Anholt drm_gem_flink_ioctl(struct drm_device *dev, void *data, 243673a394bSEric Anholt struct drm_file *file_priv) 244673a394bSEric Anholt { 245673a394bSEric Anholt struct drm_gem_flink *args = data; 246673a394bSEric Anholt struct drm_gem_object *obj; 247673a394bSEric Anholt int ret; 248673a394bSEric Anholt 249673a394bSEric Anholt if (!(dev->driver->driver_features & DRIVER_GEM)) 250673a394bSEric Anholt return -ENODEV; 251673a394bSEric Anholt 252673a394bSEric Anholt obj = drm_gem_object_lookup(dev, file_priv, args->handle); 253673a394bSEric Anholt if (obj == NULL) 254*d4e7b898SEric Anholt return -EBADF; 255673a394bSEric Anholt 256673a394bSEric Anholt again: 257673a394bSEric Anholt if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) 258673a394bSEric Anholt return -ENOMEM; 259673a394bSEric Anholt 260673a394bSEric Anholt spin_lock(&dev->object_name_lock); 261673a394bSEric Anholt if (obj->name) { 262*d4e7b898SEric Anholt args->name = obj->name; 263673a394bSEric Anholt spin_unlock(&dev->object_name_lock); 264*d4e7b898SEric Anholt return 0; 265673a394bSEric Anholt } 266673a394bSEric Anholt ret = idr_get_new_above(&dev->object_name_idr, obj, 1, 267673a394bSEric Anholt &obj->name); 268673a394bSEric Anholt spin_unlock(&dev->object_name_lock); 269673a394bSEric Anholt if (ret == -EAGAIN) 270673a394bSEric Anholt goto again; 271673a394bSEric Anholt 272673a394bSEric Anholt if (ret != 0) { 273673a394bSEric Anholt mutex_lock(&dev->struct_mutex); 274673a394bSEric Anholt drm_gem_object_unreference(obj); 275673a394bSEric Anholt mutex_unlock(&dev->struct_mutex); 276673a394bSEric Anholt return ret; 277673a394bSEric Anholt } 278673a394bSEric Anholt 279673a394bSEric Anholt /* 280673a394bSEric Anholt * Leave the reference from the lookup around as the 281673a394bSEric Anholt * name table now holds one 282673a394bSEric Anholt */ 283673a394bSEric Anholt args->name = (uint64_t) obj->name; 284673a394bSEric Anholt 285673a394bSEric Anholt return 0; 286673a394bSEric Anholt } 287673a394bSEric Anholt 288673a394bSEric Anholt /** 289673a394bSEric Anholt * Open an object using the global name, returning a handle and the size. 290673a394bSEric Anholt * 291673a394bSEric Anholt * This handle (of course) holds a reference to the object, so the object 292673a394bSEric Anholt * will not go away until the handle is deleted. 293673a394bSEric Anholt */ 294673a394bSEric Anholt int 295673a394bSEric Anholt drm_gem_open_ioctl(struct drm_device *dev, void *data, 296673a394bSEric Anholt struct drm_file *file_priv) 297673a394bSEric Anholt { 298673a394bSEric Anholt struct drm_gem_open *args = data; 299673a394bSEric Anholt struct drm_gem_object *obj; 300673a394bSEric Anholt int ret; 301673a394bSEric Anholt int handle; 302673a394bSEric Anholt 303673a394bSEric Anholt if (!(dev->driver->driver_features & DRIVER_GEM)) 304673a394bSEric Anholt return -ENODEV; 305673a394bSEric Anholt 306673a394bSEric Anholt spin_lock(&dev->object_name_lock); 307673a394bSEric Anholt obj = idr_find(&dev->object_name_idr, (int) args->name); 308673a394bSEric Anholt if (obj) 309673a394bSEric Anholt drm_gem_object_reference(obj); 310673a394bSEric Anholt spin_unlock(&dev->object_name_lock); 311673a394bSEric Anholt if (!obj) 312673a394bSEric Anholt return -ENOENT; 313673a394bSEric Anholt 314673a394bSEric Anholt ret = drm_gem_handle_create(file_priv, obj, &handle); 315673a394bSEric Anholt mutex_lock(&dev->struct_mutex); 316673a394bSEric Anholt drm_gem_object_unreference(obj); 317673a394bSEric Anholt mutex_unlock(&dev->struct_mutex); 318673a394bSEric Anholt if (ret) 319673a394bSEric Anholt return ret; 320673a394bSEric Anholt 321673a394bSEric Anholt args->handle = handle; 322673a394bSEric Anholt args->size = obj->size; 323673a394bSEric Anholt 324673a394bSEric Anholt return 0; 325673a394bSEric Anholt } 326673a394bSEric Anholt 327673a394bSEric Anholt /** 328673a394bSEric Anholt * Called at device open time, sets up the structure for handling refcounting 329673a394bSEric Anholt * of mm objects. 330673a394bSEric Anholt */ 331673a394bSEric Anholt void 332673a394bSEric Anholt drm_gem_open(struct drm_device *dev, struct drm_file *file_private) 333673a394bSEric Anholt { 334673a394bSEric Anholt idr_init(&file_private->object_idr); 335673a394bSEric Anholt spin_lock_init(&file_private->table_lock); 336673a394bSEric Anholt } 337673a394bSEric Anholt 338673a394bSEric Anholt /** 339673a394bSEric Anholt * Called at device close to release the file's 340673a394bSEric Anholt * handle references on objects. 341673a394bSEric Anholt */ 342673a394bSEric Anholt static int 343673a394bSEric Anholt drm_gem_object_release_handle(int id, void *ptr, void *data) 344673a394bSEric Anholt { 345673a394bSEric Anholt struct drm_gem_object *obj = ptr; 346673a394bSEric Anholt 347673a394bSEric Anholt drm_gem_object_handle_unreference(obj); 348673a394bSEric Anholt 349673a394bSEric Anholt return 0; 350673a394bSEric Anholt } 351673a394bSEric Anholt 352673a394bSEric Anholt /** 353673a394bSEric Anholt * Called at close time when the filp is going away. 354673a394bSEric Anholt * 355673a394bSEric Anholt * Releases any remaining references on objects by this filp. 356673a394bSEric Anholt */ 357673a394bSEric Anholt void 358673a394bSEric Anholt drm_gem_release(struct drm_device *dev, struct drm_file *file_private) 359673a394bSEric Anholt { 360673a394bSEric Anholt mutex_lock(&dev->struct_mutex); 361673a394bSEric Anholt idr_for_each(&file_private->object_idr, 362673a394bSEric Anholt &drm_gem_object_release_handle, NULL); 363673a394bSEric Anholt 364673a394bSEric Anholt idr_destroy(&file_private->object_idr); 365673a394bSEric Anholt mutex_unlock(&dev->struct_mutex); 366673a394bSEric Anholt } 367673a394bSEric Anholt 368673a394bSEric Anholt /** 369673a394bSEric Anholt * Called after the last reference to the object has been lost. 370673a394bSEric Anholt * 371673a394bSEric Anholt * Frees the object 372673a394bSEric Anholt */ 373673a394bSEric Anholt void 374673a394bSEric Anholt drm_gem_object_free(struct kref *kref) 375673a394bSEric Anholt { 376673a394bSEric Anholt struct drm_gem_object *obj = (struct drm_gem_object *) kref; 377673a394bSEric Anholt struct drm_device *dev = obj->dev; 378673a394bSEric Anholt 379673a394bSEric Anholt BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 380673a394bSEric Anholt 381673a394bSEric Anholt if (dev->driver->gem_free_object != NULL) 382673a394bSEric Anholt dev->driver->gem_free_object(obj); 383673a394bSEric Anholt 384673a394bSEric Anholt fput(obj->filp); 385673a394bSEric Anholt atomic_dec(&dev->object_count); 386673a394bSEric Anholt atomic_sub(obj->size, &dev->object_memory); 387673a394bSEric Anholt kfree(obj); 388673a394bSEric Anholt } 389673a394bSEric Anholt EXPORT_SYMBOL(drm_gem_object_free); 390673a394bSEric Anholt 391673a394bSEric Anholt /** 392673a394bSEric Anholt * Called after the last handle to the object has been closed 393673a394bSEric Anholt * 394673a394bSEric Anholt * Removes any name for the object. Note that this must be 395673a394bSEric Anholt * called before drm_gem_object_free or we'll be touching 396673a394bSEric Anholt * freed memory 397673a394bSEric Anholt */ 398673a394bSEric Anholt void 399673a394bSEric Anholt drm_gem_object_handle_free(struct kref *kref) 400673a394bSEric Anholt { 401673a394bSEric Anholt struct drm_gem_object *obj = container_of(kref, 402673a394bSEric Anholt struct drm_gem_object, 403673a394bSEric Anholt handlecount); 404673a394bSEric Anholt struct drm_device *dev = obj->dev; 405673a394bSEric Anholt 406673a394bSEric Anholt /* Remove any name for this object */ 407673a394bSEric Anholt spin_lock(&dev->object_name_lock); 408673a394bSEric Anholt if (obj->name) { 409673a394bSEric Anholt idr_remove(&dev->object_name_idr, obj->name); 410673a394bSEric Anholt spin_unlock(&dev->object_name_lock); 411673a394bSEric Anholt /* 412673a394bSEric Anholt * The object name held a reference to this object, drop 413673a394bSEric Anholt * that now. 414673a394bSEric Anholt */ 415673a394bSEric Anholt drm_gem_object_unreference(obj); 416673a394bSEric Anholt } else 417673a394bSEric Anholt spin_unlock(&dev->object_name_lock); 418673a394bSEric Anholt 419673a394bSEric Anholt } 420673a394bSEric Anholt EXPORT_SYMBOL(drm_gem_object_handle_free); 421673a394bSEric Anholt 422