1592ffb21SWarner Losh /*- 2592ffb21SWarner Losh * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3592ffb21SWarner Losh * 4592ffb21SWarner Losh * Copyright (c) 2011 The FreeBSD Foundation 5592ffb21SWarner Losh * 6592ffb21SWarner Losh * This software was developed by Konstantin Belousov under sponsorship from 7592ffb21SWarner Losh * the FreeBSD Foundation. 8592ffb21SWarner Losh * 9592ffb21SWarner Losh * Redistribution and use in source and binary forms, with or without 10592ffb21SWarner Losh * modification, are permitted provided that the following conditions 11592ffb21SWarner Losh * are met: 12592ffb21SWarner Losh * 1. Redistributions of source code must retain the above copyright 13592ffb21SWarner Losh * notice, this list of conditions and the following disclaimer. 14592ffb21SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 15592ffb21SWarner Losh * notice, this list of conditions and the following disclaimer in the 16592ffb21SWarner Losh * documentation and/or other materials provided with the distribution. 17592ffb21SWarner Losh * 18592ffb21SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19592ffb21SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20592ffb21SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21592ffb21SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22592ffb21SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23592ffb21SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24592ffb21SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25592ffb21SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26592ffb21SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27592ffb21SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28592ffb21SWarner Losh * SUCH DAMAGE. 29592ffb21SWarner Losh */ 30592ffb21SWarner Losh 31592ffb21SWarner Losh #include <sys/cdefs.h> 32592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 33592ffb21SWarner Losh 34592ffb21SWarner Losh #include "opt_vm.h" 35592ffb21SWarner Losh 36592ffb21SWarner Losh #include <sys/param.h> 37592ffb21SWarner Losh #include <sys/systm.h> 38592ffb21SWarner Losh #include <sys/limits.h> 39592ffb21SWarner Losh #include <sys/lock.h> 40592ffb21SWarner Losh #include <sys/mutex.h> 41592ffb21SWarner Losh 42592ffb21SWarner Losh #include <vm/vm.h> 43592ffb21SWarner Losh #include <vm/vm_page.h> 44592ffb21SWarner Losh 45592ffb21SWarner Losh #include <dev/drm2/drmP.h> 46592ffb21SWarner Losh #include <dev/drm2/drm.h> 47592ffb21SWarner Losh #include <dev/drm2/drm_sarea.h> 48592ffb21SWarner Losh 49592ffb21SWarner Losh /* 50592ffb21SWarner Losh * We make up offsets for buffer objects so we can recognize them at 51592ffb21SWarner Losh * mmap time. 52592ffb21SWarner Losh */ 53592ffb21SWarner Losh 54592ffb21SWarner Losh /* pgoff in mmap is an unsigned long, so we need to make sure that 55592ffb21SWarner Losh * the faked up offset will fit 56592ffb21SWarner Losh */ 57592ffb21SWarner Losh 58592ffb21SWarner Losh #if BITS_PER_LONG == 64 59592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) 60592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) 61592ffb21SWarner Losh #else 62592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1) 63592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) 64592ffb21SWarner Losh #endif 65592ffb21SWarner Losh 66592ffb21SWarner Losh /** 67592ffb21SWarner Losh * Initialize the GEM device fields 68592ffb21SWarner Losh */ 69592ffb21SWarner Losh 70592ffb21SWarner Losh int 71592ffb21SWarner Losh drm_gem_init(struct drm_device *dev) 72592ffb21SWarner Losh { 73592ffb21SWarner Losh struct drm_gem_mm *mm; 74592ffb21SWarner Losh 75592ffb21SWarner Losh drm_gem_names_init(&dev->object_names); 76592ffb21SWarner Losh 77592ffb21SWarner Losh mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_NOWAIT); 78592ffb21SWarner Losh if (!mm) { 79592ffb21SWarner Losh DRM_ERROR("out of memory\n"); 80592ffb21SWarner Losh return -ENOMEM; 81592ffb21SWarner Losh } 82592ffb21SWarner Losh 83592ffb21SWarner Losh dev->mm_private = mm; 84592ffb21SWarner Losh 85592ffb21SWarner Losh if (drm_ht_create(&mm->offset_hash, 19)) { 86592ffb21SWarner Losh free(mm, DRM_MEM_DRIVER); 87592ffb21SWarner Losh return -ENOMEM; 88592ffb21SWarner Losh } 89592ffb21SWarner Losh 90592ffb21SWarner Losh mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL); 91592ffb21SWarner Losh 92592ffb21SWarner Losh return 0; 93592ffb21SWarner Losh } 94592ffb21SWarner Losh 95592ffb21SWarner Losh void 96592ffb21SWarner Losh drm_gem_destroy(struct drm_device *dev) 97592ffb21SWarner Losh { 98592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 99592ffb21SWarner Losh 100592ffb21SWarner Losh dev->mm_private = NULL; 101592ffb21SWarner Losh drm_ht_remove(&mm->offset_hash); 102592ffb21SWarner Losh delete_unrhdr(mm->idxunr); 103592ffb21SWarner Losh free(mm, DRM_MEM_DRIVER); 104592ffb21SWarner Losh drm_gem_names_fini(&dev->object_names); 105592ffb21SWarner Losh } 106592ffb21SWarner Losh 107592ffb21SWarner Losh int drm_gem_object_init(struct drm_device *dev, 108592ffb21SWarner Losh struct drm_gem_object *obj, size_t size) 109592ffb21SWarner Losh { 110592ffb21SWarner Losh KASSERT((size & (PAGE_SIZE - 1)) == 0, 111592ffb21SWarner Losh ("Bad size %ju", (uintmax_t)size)); 112592ffb21SWarner Losh 113592ffb21SWarner Losh obj->dev = dev; 114*6b389740SMark Johnston obj->vm_obj = vm_pager_allocate(OBJT_SWAP, NULL, size, 115592ffb21SWarner Losh VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred); 116592ffb21SWarner Losh 117592ffb21SWarner Losh obj->refcount = 1; 118592ffb21SWarner Losh obj->handle_count = 0; 119592ffb21SWarner Losh obj->size = size; 120592ffb21SWarner Losh 121592ffb21SWarner Losh return 0; 122592ffb21SWarner Losh } 123592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_init); 124592ffb21SWarner Losh 125592ffb21SWarner Losh /** 126592ffb21SWarner Losh * Initialize an already allocated GEM object of the specified size with 127592ffb21SWarner Losh * no GEM provided backing store. Instead the caller is responsible for 128592ffb21SWarner Losh * backing the object and handling it. 129592ffb21SWarner Losh */ 130592ffb21SWarner Losh int drm_gem_private_object_init(struct drm_device *dev, 131592ffb21SWarner Losh struct drm_gem_object *obj, size_t size) 132592ffb21SWarner Losh { 133592ffb21SWarner Losh MPASS((size & (PAGE_SIZE - 1)) == 0); 134592ffb21SWarner Losh 135592ffb21SWarner Losh obj->dev = dev; 136592ffb21SWarner Losh obj->vm_obj = NULL; 137592ffb21SWarner Losh 138592ffb21SWarner Losh obj->refcount = 1; 139592ffb21SWarner Losh atomic_store_rel_int(&obj->handle_count, 0); 140592ffb21SWarner Losh obj->size = size; 141592ffb21SWarner Losh 142592ffb21SWarner Losh return 0; 143592ffb21SWarner Losh } 144592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_private_object_init); 145592ffb21SWarner Losh 146592ffb21SWarner Losh struct drm_gem_object * 147592ffb21SWarner Losh drm_gem_object_alloc(struct drm_device *dev, size_t size) 148592ffb21SWarner Losh { 149592ffb21SWarner Losh struct drm_gem_object *obj; 150592ffb21SWarner Losh 151592ffb21SWarner Losh obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 152592ffb21SWarner Losh if (!obj) 153592ffb21SWarner Losh goto free; 154592ffb21SWarner Losh 155592ffb21SWarner Losh if (drm_gem_object_init(dev, obj, size) != 0) 156592ffb21SWarner Losh goto free; 157592ffb21SWarner Losh 158592ffb21SWarner Losh if (dev->driver->gem_init_object != NULL && 159592ffb21SWarner Losh dev->driver->gem_init_object(obj) != 0) { 160592ffb21SWarner Losh goto dealloc; 161592ffb21SWarner Losh } 162592ffb21SWarner Losh return obj; 163592ffb21SWarner Losh dealloc: 164592ffb21SWarner Losh vm_object_deallocate(obj->vm_obj); 165592ffb21SWarner Losh free: 166592ffb21SWarner Losh free(obj, DRM_MEM_DRIVER); 167592ffb21SWarner Losh return NULL; 168592ffb21SWarner Losh } 169592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_alloc); 170592ffb21SWarner Losh 171592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 172592ffb21SWarner Losh static void 173592ffb21SWarner Losh drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) 174592ffb21SWarner Losh { 175592ffb21SWarner Losh if (obj->import_attach) { 176592ffb21SWarner Losh drm_prime_remove_buf_handle(&filp->prime, 177592ffb21SWarner Losh obj->import_attach->dmabuf); 178592ffb21SWarner Losh } 179592ffb21SWarner Losh if (obj->export_dma_buf) { 180592ffb21SWarner Losh drm_prime_remove_buf_handle(&filp->prime, 181592ffb21SWarner Losh obj->export_dma_buf); 182592ffb21SWarner Losh } 183592ffb21SWarner Losh } 184592ffb21SWarner Losh #endif 185592ffb21SWarner Losh 186592ffb21SWarner Losh /** 187592ffb21SWarner Losh * Removes the mapping from handle to filp for this object. 188592ffb21SWarner Losh */ 189592ffb21SWarner Losh int 190592ffb21SWarner Losh drm_gem_handle_delete(struct drm_file *filp, u32 handle) 191592ffb21SWarner Losh { 192592ffb21SWarner Losh struct drm_device *dev; 193592ffb21SWarner Losh struct drm_gem_object *obj; 194592ffb21SWarner Losh 195592ffb21SWarner Losh obj = drm_gem_names_remove(&filp->object_names, handle); 196592ffb21SWarner Losh if (obj == NULL) { 197592ffb21SWarner Losh return -EINVAL; 198592ffb21SWarner Losh } 199592ffb21SWarner Losh dev = obj->dev; 200592ffb21SWarner Losh 201592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 202592ffb21SWarner Losh drm_gem_remove_prime_handles(obj, filp); 203592ffb21SWarner Losh #endif 204592ffb21SWarner Losh 205592ffb21SWarner Losh if (dev->driver->gem_close_object) 206592ffb21SWarner Losh dev->driver->gem_close_object(obj, filp); 207592ffb21SWarner Losh drm_gem_object_handle_unreference_unlocked(obj); 208592ffb21SWarner Losh 209592ffb21SWarner Losh return 0; 210592ffb21SWarner Losh } 211592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_delete); 212592ffb21SWarner Losh 213592ffb21SWarner Losh /** 214592ffb21SWarner Losh * Create a handle for this object. This adds a handle reference 215592ffb21SWarner Losh * to the object, which includes a regular reference count. Callers 216592ffb21SWarner Losh * will likely want to dereference the object afterwards. 217592ffb21SWarner Losh */ 218592ffb21SWarner Losh int 219592ffb21SWarner Losh drm_gem_handle_create(struct drm_file *file_priv, 220592ffb21SWarner Losh struct drm_gem_object *obj, 221592ffb21SWarner Losh u32 *handlep) 222592ffb21SWarner Losh { 223592ffb21SWarner Losh struct drm_device *dev = obj->dev; 224592ffb21SWarner Losh int ret; 225592ffb21SWarner Losh 226592ffb21SWarner Losh *handlep = 0; 227592ffb21SWarner Losh ret = drm_gem_name_create(&file_priv->object_names, obj, handlep); 228592ffb21SWarner Losh if (ret != 0) 229592ffb21SWarner Losh return ret; 230592ffb21SWarner Losh 231592ffb21SWarner Losh drm_gem_object_handle_reference(obj); 232592ffb21SWarner Losh 233592ffb21SWarner Losh if (dev->driver->gem_open_object) { 234592ffb21SWarner Losh ret = dev->driver->gem_open_object(obj, file_priv); 235592ffb21SWarner Losh if (ret) { 236592ffb21SWarner Losh drm_gem_handle_delete(file_priv, *handlep); 237592ffb21SWarner Losh return ret; 238592ffb21SWarner Losh } 239592ffb21SWarner Losh } 240592ffb21SWarner Losh 241592ffb21SWarner Losh return 0; 242592ffb21SWarner Losh } 243592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_create); 244592ffb21SWarner Losh 245592ffb21SWarner Losh void 246592ffb21SWarner Losh drm_gem_free_mmap_offset(struct drm_gem_object *obj) 247592ffb21SWarner Losh { 248592ffb21SWarner Losh struct drm_device *dev = obj->dev; 249592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 250592ffb21SWarner Losh struct drm_hash_item *list = &obj->map_list; 251592ffb21SWarner Losh 252592ffb21SWarner Losh if (!obj->on_map) 253592ffb21SWarner Losh return; 254592ffb21SWarner Losh 255592ffb21SWarner Losh drm_ht_remove_item(&mm->offset_hash, list); 256592ffb21SWarner Losh free_unr(mm->idxunr, list->key); 257592ffb21SWarner Losh obj->on_map = false; 258592ffb21SWarner Losh } 259592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_free_mmap_offset); 260592ffb21SWarner Losh 261592ffb21SWarner Losh int 262592ffb21SWarner Losh drm_gem_create_mmap_offset(struct drm_gem_object *obj) 263592ffb21SWarner Losh { 264592ffb21SWarner Losh struct drm_device *dev = obj->dev; 265592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 266592ffb21SWarner Losh int ret; 267592ffb21SWarner Losh 268592ffb21SWarner Losh if (obj->on_map) 269592ffb21SWarner Losh return 0; 270592ffb21SWarner Losh 271592ffb21SWarner Losh obj->map_list.key = alloc_unr(mm->idxunr); 272592ffb21SWarner Losh ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list); 273592ffb21SWarner Losh if (ret) { 274592ffb21SWarner Losh DRM_ERROR("failed to add to map hash\n"); 275592ffb21SWarner Losh free_unr(mm->idxunr, obj->map_list.key); 276592ffb21SWarner Losh return ret; 277592ffb21SWarner Losh } 278592ffb21SWarner Losh obj->on_map = true; 279592ffb21SWarner Losh 280592ffb21SWarner Losh return 0; 281592ffb21SWarner Losh } 282592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_create_mmap_offset); 283592ffb21SWarner Losh 284592ffb21SWarner Losh /** Returns a reference to the object named by the handle. */ 285592ffb21SWarner Losh struct drm_gem_object * 286592ffb21SWarner Losh drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, 287592ffb21SWarner Losh u32 handle) 288592ffb21SWarner Losh { 289592ffb21SWarner Losh struct drm_gem_object *obj; 290592ffb21SWarner Losh 291592ffb21SWarner Losh obj = drm_gem_name_ref(&filp->object_names, handle, 292592ffb21SWarner Losh (void (*)(void *))drm_gem_object_reference); 293592ffb21SWarner Losh 294592ffb21SWarner Losh return obj; 295592ffb21SWarner Losh } 296592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_lookup); 297592ffb21SWarner Losh 298592ffb21SWarner Losh int 299592ffb21SWarner Losh drm_gem_close_ioctl(struct drm_device *dev, void *data, 300592ffb21SWarner Losh struct drm_file *file_priv) 301592ffb21SWarner Losh { 302592ffb21SWarner Losh struct drm_gem_close *args = data; 303592ffb21SWarner Losh int ret; 304592ffb21SWarner Losh 305592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 306592ffb21SWarner Losh return -ENODEV; 307592ffb21SWarner Losh 308592ffb21SWarner Losh ret = drm_gem_handle_delete(file_priv, args->handle); 309592ffb21SWarner Losh 310592ffb21SWarner Losh return ret; 311592ffb21SWarner Losh } 312592ffb21SWarner Losh 313592ffb21SWarner Losh int 314592ffb21SWarner Losh drm_gem_flink_ioctl(struct drm_device *dev, void *data, 315592ffb21SWarner Losh struct drm_file *file_priv) 316592ffb21SWarner Losh { 317592ffb21SWarner Losh struct drm_gem_flink *args = data; 318592ffb21SWarner Losh struct drm_gem_object *obj; 319592ffb21SWarner Losh int ret; 320592ffb21SWarner Losh 321592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 322592ffb21SWarner Losh return -ENODEV; 323592ffb21SWarner Losh 324592ffb21SWarner Losh obj = drm_gem_object_lookup(dev, file_priv, args->handle); 325592ffb21SWarner Losh if (obj == NULL) 326592ffb21SWarner Losh return -ENOENT; 327592ffb21SWarner Losh 328592ffb21SWarner Losh ret = drm_gem_name_create(&dev->object_names, obj, &obj->name); 329592ffb21SWarner Losh if (ret != 0) { 330592ffb21SWarner Losh if (ret == -EALREADY) 331592ffb21SWarner Losh ret = 0; 332592ffb21SWarner Losh drm_gem_object_unreference_unlocked(obj); 333592ffb21SWarner Losh } 334592ffb21SWarner Losh if (ret == 0) 335592ffb21SWarner Losh args->name = obj->name; 336592ffb21SWarner Losh return ret; 337592ffb21SWarner Losh } 338592ffb21SWarner Losh 339592ffb21SWarner Losh int 340592ffb21SWarner Losh drm_gem_open_ioctl(struct drm_device *dev, void *data, 341592ffb21SWarner Losh struct drm_file *file_priv) 342592ffb21SWarner Losh { 343592ffb21SWarner Losh struct drm_gem_open *args = data; 344592ffb21SWarner Losh struct drm_gem_object *obj; 345592ffb21SWarner Losh int ret; 346592ffb21SWarner Losh u32 handle; 347592ffb21SWarner Losh 348592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 349592ffb21SWarner Losh return -ENODEV; 350592ffb21SWarner Losh 351592ffb21SWarner Losh obj = drm_gem_name_ref(&dev->object_names, args->name, 352592ffb21SWarner Losh (void (*)(void *))drm_gem_object_reference); 353592ffb21SWarner Losh if (!obj) 354592ffb21SWarner Losh return -ENOENT; 355592ffb21SWarner Losh 356592ffb21SWarner Losh ret = drm_gem_handle_create(file_priv, obj, &handle); 357592ffb21SWarner Losh drm_gem_object_unreference_unlocked(obj); 358592ffb21SWarner Losh if (ret) 359592ffb21SWarner Losh return ret; 360592ffb21SWarner Losh 361592ffb21SWarner Losh args->handle = handle; 362592ffb21SWarner Losh args->size = obj->size; 363592ffb21SWarner Losh 364592ffb21SWarner Losh return 0; 365592ffb21SWarner Losh } 366592ffb21SWarner Losh 367592ffb21SWarner Losh void 368592ffb21SWarner Losh drm_gem_open(struct drm_device *dev, struct drm_file *file_private) 369592ffb21SWarner Losh { 370592ffb21SWarner Losh 371592ffb21SWarner Losh drm_gem_names_init(&file_private->object_names); 372592ffb21SWarner Losh } 373592ffb21SWarner Losh 374592ffb21SWarner Losh static int 375592ffb21SWarner Losh drm_gem_object_release_handle(uint32_t name, void *ptr, void *data) 376592ffb21SWarner Losh { 377592ffb21SWarner Losh struct drm_file *file_priv = data; 378592ffb21SWarner Losh struct drm_gem_object *obj = ptr; 379592ffb21SWarner Losh struct drm_device *dev = obj->dev; 380592ffb21SWarner Losh 381592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 382592ffb21SWarner Losh drm_gem_remove_prime_handles(obj, file_priv); 383592ffb21SWarner Losh #endif 384592ffb21SWarner Losh 385592ffb21SWarner Losh if (dev->driver->gem_close_object) 386592ffb21SWarner Losh dev->driver->gem_close_object(obj, file_priv); 387592ffb21SWarner Losh 388592ffb21SWarner Losh drm_gem_object_handle_unreference_unlocked(obj); 389592ffb21SWarner Losh 390592ffb21SWarner Losh return 0; 391592ffb21SWarner Losh } 392592ffb21SWarner Losh 393592ffb21SWarner Losh void 394592ffb21SWarner Losh drm_gem_release(struct drm_device *dev, struct drm_file *file_private) 395592ffb21SWarner Losh { 396592ffb21SWarner Losh drm_gem_names_foreach(&file_private->object_names, 397592ffb21SWarner Losh drm_gem_object_release_handle, file_private); 398592ffb21SWarner Losh 399592ffb21SWarner Losh drm_gem_names_fini(&file_private->object_names); 400592ffb21SWarner Losh } 401592ffb21SWarner Losh 402592ffb21SWarner Losh void 403592ffb21SWarner Losh drm_gem_object_release(struct drm_gem_object *obj) 404592ffb21SWarner Losh { 405592ffb21SWarner Losh 406592ffb21SWarner Losh /* 407592ffb21SWarner Losh * obj->vm_obj can be NULL for private gem objects. 408592ffb21SWarner Losh */ 409592ffb21SWarner Losh vm_object_deallocate(obj->vm_obj); 410592ffb21SWarner Losh } 411592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_release); 412592ffb21SWarner Losh 413592ffb21SWarner Losh void 414592ffb21SWarner Losh drm_gem_object_free(struct drm_gem_object *obj) 415592ffb21SWarner Losh { 416592ffb21SWarner Losh struct drm_device *dev = obj->dev; 417592ffb21SWarner Losh 418592ffb21SWarner Losh DRM_LOCK_ASSERT(dev); 419592ffb21SWarner Losh if (dev->driver->gem_free_object != NULL) 420592ffb21SWarner Losh dev->driver->gem_free_object(obj); 421592ffb21SWarner Losh } 422592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_free); 423592ffb21SWarner Losh 424592ffb21SWarner Losh void drm_gem_object_handle_free(struct drm_gem_object *obj) 425592ffb21SWarner Losh { 426592ffb21SWarner Losh struct drm_device *dev = obj->dev; 427592ffb21SWarner Losh struct drm_gem_object *obj1; 428592ffb21SWarner Losh 429592ffb21SWarner Losh if (obj->name) { 430592ffb21SWarner Losh obj1 = drm_gem_names_remove(&dev->object_names, obj->name); 431592ffb21SWarner Losh obj->name = 0; 432592ffb21SWarner Losh drm_gem_object_unreference(obj1); 433592ffb21SWarner Losh } 434592ffb21SWarner Losh } 435592ffb21SWarner Losh 436592ffb21SWarner Losh static struct drm_gem_object * 437592ffb21SWarner Losh drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset) 438592ffb21SWarner Losh { 439592ffb21SWarner Losh struct drm_gem_object *obj; 440592ffb21SWarner Losh struct drm_gem_mm *mm; 441592ffb21SWarner Losh struct drm_hash_item *map_list; 442592ffb21SWarner Losh 443592ffb21SWarner Losh if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY) 444592ffb21SWarner Losh return (NULL); 445592ffb21SWarner Losh offset &= ~DRM_GEM_MAPPING_KEY; 446592ffb21SWarner Losh mm = dev->mm_private; 447592ffb21SWarner Losh if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset), 448592ffb21SWarner Losh &map_list) != 0) { 449592ffb21SWarner Losh DRM_DEBUG("drm_gem_object_from_offset: offset 0x%jx obj not found\n", 450592ffb21SWarner Losh (uintmax_t)offset); 451592ffb21SWarner Losh return (NULL); 452592ffb21SWarner Losh } 453592ffb21SWarner Losh obj = __containerof(map_list, struct drm_gem_object, map_list); 454592ffb21SWarner Losh return (obj); 455592ffb21SWarner Losh } 456592ffb21SWarner Losh 457592ffb21SWarner Losh int 458592ffb21SWarner Losh drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size, 459592ffb21SWarner Losh struct vm_object **obj_res, int nprot) 460592ffb21SWarner Losh { 461592ffb21SWarner Losh struct drm_gem_object *gem_obj; 462592ffb21SWarner Losh struct vm_object *vm_obj; 463592ffb21SWarner Losh 464592ffb21SWarner Losh DRM_LOCK(dev); 465592ffb21SWarner Losh gem_obj = drm_gem_object_from_offset(dev, *offset); 466592ffb21SWarner Losh if (gem_obj == NULL) { 467592ffb21SWarner Losh DRM_UNLOCK(dev); 468592ffb21SWarner Losh return (-ENODEV); 469592ffb21SWarner Losh } 470592ffb21SWarner Losh drm_gem_object_reference(gem_obj); 471592ffb21SWarner Losh DRM_UNLOCK(dev); 472592ffb21SWarner Losh vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE, 473592ffb21SWarner Losh dev->driver->gem_pager_ops, size, nprot, 474592ffb21SWarner Losh DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred); 475592ffb21SWarner Losh if (vm_obj == NULL) { 476592ffb21SWarner Losh drm_gem_object_unreference_unlocked(gem_obj); 477592ffb21SWarner Losh return (-EINVAL); 478592ffb21SWarner Losh } 479592ffb21SWarner Losh *offset = DRM_GEM_MAPPING_MAPOFF(*offset); 480592ffb21SWarner Losh *obj_res = vm_obj; 481592ffb21SWarner Losh return (0); 482592ffb21SWarner Losh } 483592ffb21SWarner Losh 484592ffb21SWarner Losh void 485592ffb21SWarner Losh drm_gem_pager_dtr(void *handle) 486592ffb21SWarner Losh { 487592ffb21SWarner Losh struct drm_gem_object *obj; 488592ffb21SWarner Losh struct drm_device *dev; 489592ffb21SWarner Losh 490592ffb21SWarner Losh obj = handle; 491592ffb21SWarner Losh dev = obj->dev; 492592ffb21SWarner Losh 493592ffb21SWarner Losh DRM_LOCK(dev); 494592ffb21SWarner Losh drm_gem_free_mmap_offset(obj); 495592ffb21SWarner Losh drm_gem_object_unreference(obj); 496592ffb21SWarner Losh DRM_UNLOCK(dev); 497592ffb21SWarner Losh } 498