1*592ffb21SWarner Losh /*- 2*592ffb21SWarner Losh * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*592ffb21SWarner Losh * 4*592ffb21SWarner Losh * Copyright (c) 2011 The FreeBSD Foundation 5*592ffb21SWarner Losh * All rights reserved. 6*592ffb21SWarner Losh * 7*592ffb21SWarner Losh * This software was developed by Konstantin Belousov under sponsorship from 8*592ffb21SWarner Losh * the FreeBSD Foundation. 9*592ffb21SWarner Losh * 10*592ffb21SWarner Losh * Redistribution and use in source and binary forms, with or without 11*592ffb21SWarner Losh * modification, are permitted provided that the following conditions 12*592ffb21SWarner Losh * are met: 13*592ffb21SWarner Losh * 1. Redistributions of source code must retain the above copyright 14*592ffb21SWarner Losh * notice, this list of conditions and the following disclaimer. 15*592ffb21SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 16*592ffb21SWarner Losh * notice, this list of conditions and the following disclaimer in the 17*592ffb21SWarner Losh * documentation and/or other materials provided with the distribution. 18*592ffb21SWarner Losh * 19*592ffb21SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20*592ffb21SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*592ffb21SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*592ffb21SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23*592ffb21SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*592ffb21SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*592ffb21SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*592ffb21SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*592ffb21SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*592ffb21SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29*592ffb21SWarner Losh * SUCH DAMAGE. 30*592ffb21SWarner Losh */ 31*592ffb21SWarner Losh 32*592ffb21SWarner Losh #include <sys/cdefs.h> 33*592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 34*592ffb21SWarner Losh 35*592ffb21SWarner Losh #include "opt_vm.h" 36*592ffb21SWarner Losh 37*592ffb21SWarner Losh #include <sys/param.h> 38*592ffb21SWarner Losh #include <sys/systm.h> 39*592ffb21SWarner Losh #include <sys/limits.h> 40*592ffb21SWarner Losh #include <sys/lock.h> 41*592ffb21SWarner Losh #include <sys/mutex.h> 42*592ffb21SWarner Losh 43*592ffb21SWarner Losh #include <vm/vm.h> 44*592ffb21SWarner Losh #include <vm/vm_page.h> 45*592ffb21SWarner Losh 46*592ffb21SWarner Losh #include <dev/drm2/drmP.h> 47*592ffb21SWarner Losh #include <dev/drm2/drm.h> 48*592ffb21SWarner Losh #include <dev/drm2/drm_sarea.h> 49*592ffb21SWarner Losh 50*592ffb21SWarner Losh /* 51*592ffb21SWarner Losh * We make up offsets for buffer objects so we can recognize them at 52*592ffb21SWarner Losh * mmap time. 53*592ffb21SWarner Losh */ 54*592ffb21SWarner Losh 55*592ffb21SWarner Losh /* pgoff in mmap is an unsigned long, so we need to make sure that 56*592ffb21SWarner Losh * the faked up offset will fit 57*592ffb21SWarner Losh */ 58*592ffb21SWarner Losh 59*592ffb21SWarner Losh #if BITS_PER_LONG == 64 60*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) 61*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) 62*592ffb21SWarner Losh #else 63*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1) 64*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) 65*592ffb21SWarner Losh #endif 66*592ffb21SWarner Losh 67*592ffb21SWarner Losh /** 68*592ffb21SWarner Losh * Initialize the GEM device fields 69*592ffb21SWarner Losh */ 70*592ffb21SWarner Losh 71*592ffb21SWarner Losh int 72*592ffb21SWarner Losh drm_gem_init(struct drm_device *dev) 73*592ffb21SWarner Losh { 74*592ffb21SWarner Losh struct drm_gem_mm *mm; 75*592ffb21SWarner Losh 76*592ffb21SWarner Losh drm_gem_names_init(&dev->object_names); 77*592ffb21SWarner Losh 78*592ffb21SWarner Losh mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_NOWAIT); 79*592ffb21SWarner Losh if (!mm) { 80*592ffb21SWarner Losh DRM_ERROR("out of memory\n"); 81*592ffb21SWarner Losh return -ENOMEM; 82*592ffb21SWarner Losh } 83*592ffb21SWarner Losh 84*592ffb21SWarner Losh dev->mm_private = mm; 85*592ffb21SWarner Losh 86*592ffb21SWarner Losh if (drm_ht_create(&mm->offset_hash, 19)) { 87*592ffb21SWarner Losh free(mm, DRM_MEM_DRIVER); 88*592ffb21SWarner Losh return -ENOMEM; 89*592ffb21SWarner Losh } 90*592ffb21SWarner Losh 91*592ffb21SWarner Losh mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL); 92*592ffb21SWarner Losh 93*592ffb21SWarner Losh return 0; 94*592ffb21SWarner Losh } 95*592ffb21SWarner Losh 96*592ffb21SWarner Losh void 97*592ffb21SWarner Losh drm_gem_destroy(struct drm_device *dev) 98*592ffb21SWarner Losh { 99*592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 100*592ffb21SWarner Losh 101*592ffb21SWarner Losh dev->mm_private = NULL; 102*592ffb21SWarner Losh drm_ht_remove(&mm->offset_hash); 103*592ffb21SWarner Losh delete_unrhdr(mm->idxunr); 104*592ffb21SWarner Losh free(mm, DRM_MEM_DRIVER); 105*592ffb21SWarner Losh drm_gem_names_fini(&dev->object_names); 106*592ffb21SWarner Losh } 107*592ffb21SWarner Losh 108*592ffb21SWarner Losh int drm_gem_object_init(struct drm_device *dev, 109*592ffb21SWarner Losh struct drm_gem_object *obj, size_t size) 110*592ffb21SWarner Losh { 111*592ffb21SWarner Losh KASSERT((size & (PAGE_SIZE - 1)) == 0, 112*592ffb21SWarner Losh ("Bad size %ju", (uintmax_t)size)); 113*592ffb21SWarner Losh 114*592ffb21SWarner Losh obj->dev = dev; 115*592ffb21SWarner Losh obj->vm_obj = vm_pager_allocate(OBJT_DEFAULT, NULL, size, 116*592ffb21SWarner Losh VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred); 117*592ffb21SWarner Losh 118*592ffb21SWarner Losh obj->refcount = 1; 119*592ffb21SWarner Losh obj->handle_count = 0; 120*592ffb21SWarner Losh obj->size = size; 121*592ffb21SWarner Losh 122*592ffb21SWarner Losh return 0; 123*592ffb21SWarner Losh } 124*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_init); 125*592ffb21SWarner Losh 126*592ffb21SWarner Losh /** 127*592ffb21SWarner Losh * Initialize an already allocated GEM object of the specified size with 128*592ffb21SWarner Losh * no GEM provided backing store. Instead the caller is responsible for 129*592ffb21SWarner Losh * backing the object and handling it. 130*592ffb21SWarner Losh */ 131*592ffb21SWarner Losh int drm_gem_private_object_init(struct drm_device *dev, 132*592ffb21SWarner Losh struct drm_gem_object *obj, size_t size) 133*592ffb21SWarner Losh { 134*592ffb21SWarner Losh MPASS((size & (PAGE_SIZE - 1)) == 0); 135*592ffb21SWarner Losh 136*592ffb21SWarner Losh obj->dev = dev; 137*592ffb21SWarner Losh obj->vm_obj = NULL; 138*592ffb21SWarner Losh 139*592ffb21SWarner Losh obj->refcount = 1; 140*592ffb21SWarner Losh atomic_store_rel_int(&obj->handle_count, 0); 141*592ffb21SWarner Losh obj->size = size; 142*592ffb21SWarner Losh 143*592ffb21SWarner Losh return 0; 144*592ffb21SWarner Losh } 145*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_private_object_init); 146*592ffb21SWarner Losh 147*592ffb21SWarner Losh struct drm_gem_object * 148*592ffb21SWarner Losh drm_gem_object_alloc(struct drm_device *dev, size_t size) 149*592ffb21SWarner Losh { 150*592ffb21SWarner Losh struct drm_gem_object *obj; 151*592ffb21SWarner Losh 152*592ffb21SWarner Losh obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 153*592ffb21SWarner Losh if (!obj) 154*592ffb21SWarner Losh goto free; 155*592ffb21SWarner Losh 156*592ffb21SWarner Losh if (drm_gem_object_init(dev, obj, size) != 0) 157*592ffb21SWarner Losh goto free; 158*592ffb21SWarner Losh 159*592ffb21SWarner Losh if (dev->driver->gem_init_object != NULL && 160*592ffb21SWarner Losh dev->driver->gem_init_object(obj) != 0) { 161*592ffb21SWarner Losh goto dealloc; 162*592ffb21SWarner Losh } 163*592ffb21SWarner Losh return obj; 164*592ffb21SWarner Losh dealloc: 165*592ffb21SWarner Losh vm_object_deallocate(obj->vm_obj); 166*592ffb21SWarner Losh free: 167*592ffb21SWarner Losh free(obj, DRM_MEM_DRIVER); 168*592ffb21SWarner Losh return NULL; 169*592ffb21SWarner Losh } 170*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_alloc); 171*592ffb21SWarner Losh 172*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 173*592ffb21SWarner Losh static void 174*592ffb21SWarner Losh drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) 175*592ffb21SWarner Losh { 176*592ffb21SWarner Losh if (obj->import_attach) { 177*592ffb21SWarner Losh drm_prime_remove_buf_handle(&filp->prime, 178*592ffb21SWarner Losh obj->import_attach->dmabuf); 179*592ffb21SWarner Losh } 180*592ffb21SWarner Losh if (obj->export_dma_buf) { 181*592ffb21SWarner Losh drm_prime_remove_buf_handle(&filp->prime, 182*592ffb21SWarner Losh obj->export_dma_buf); 183*592ffb21SWarner Losh } 184*592ffb21SWarner Losh } 185*592ffb21SWarner Losh #endif 186*592ffb21SWarner Losh 187*592ffb21SWarner Losh /** 188*592ffb21SWarner Losh * Removes the mapping from handle to filp for this object. 189*592ffb21SWarner Losh */ 190*592ffb21SWarner Losh int 191*592ffb21SWarner Losh drm_gem_handle_delete(struct drm_file *filp, u32 handle) 192*592ffb21SWarner Losh { 193*592ffb21SWarner Losh struct drm_device *dev; 194*592ffb21SWarner Losh struct drm_gem_object *obj; 195*592ffb21SWarner Losh 196*592ffb21SWarner Losh obj = drm_gem_names_remove(&filp->object_names, handle); 197*592ffb21SWarner Losh if (obj == NULL) { 198*592ffb21SWarner Losh return -EINVAL; 199*592ffb21SWarner Losh } 200*592ffb21SWarner Losh dev = obj->dev; 201*592ffb21SWarner Losh 202*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 203*592ffb21SWarner Losh drm_gem_remove_prime_handles(obj, filp); 204*592ffb21SWarner Losh #endif 205*592ffb21SWarner Losh 206*592ffb21SWarner Losh if (dev->driver->gem_close_object) 207*592ffb21SWarner Losh dev->driver->gem_close_object(obj, filp); 208*592ffb21SWarner Losh drm_gem_object_handle_unreference_unlocked(obj); 209*592ffb21SWarner Losh 210*592ffb21SWarner Losh return 0; 211*592ffb21SWarner Losh } 212*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_delete); 213*592ffb21SWarner Losh 214*592ffb21SWarner Losh /** 215*592ffb21SWarner Losh * Create a handle for this object. This adds a handle reference 216*592ffb21SWarner Losh * to the object, which includes a regular reference count. Callers 217*592ffb21SWarner Losh * will likely want to dereference the object afterwards. 218*592ffb21SWarner Losh */ 219*592ffb21SWarner Losh int 220*592ffb21SWarner Losh drm_gem_handle_create(struct drm_file *file_priv, 221*592ffb21SWarner Losh struct drm_gem_object *obj, 222*592ffb21SWarner Losh u32 *handlep) 223*592ffb21SWarner Losh { 224*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 225*592ffb21SWarner Losh int ret; 226*592ffb21SWarner Losh 227*592ffb21SWarner Losh *handlep = 0; 228*592ffb21SWarner Losh ret = drm_gem_name_create(&file_priv->object_names, obj, handlep); 229*592ffb21SWarner Losh if (ret != 0) 230*592ffb21SWarner Losh return ret; 231*592ffb21SWarner Losh 232*592ffb21SWarner Losh drm_gem_object_handle_reference(obj); 233*592ffb21SWarner Losh 234*592ffb21SWarner Losh if (dev->driver->gem_open_object) { 235*592ffb21SWarner Losh ret = dev->driver->gem_open_object(obj, file_priv); 236*592ffb21SWarner Losh if (ret) { 237*592ffb21SWarner Losh drm_gem_handle_delete(file_priv, *handlep); 238*592ffb21SWarner Losh return ret; 239*592ffb21SWarner Losh } 240*592ffb21SWarner Losh } 241*592ffb21SWarner Losh 242*592ffb21SWarner Losh return 0; 243*592ffb21SWarner Losh } 244*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_create); 245*592ffb21SWarner Losh 246*592ffb21SWarner Losh void 247*592ffb21SWarner Losh drm_gem_free_mmap_offset(struct drm_gem_object *obj) 248*592ffb21SWarner Losh { 249*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 250*592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 251*592ffb21SWarner Losh struct drm_hash_item *list = &obj->map_list; 252*592ffb21SWarner Losh 253*592ffb21SWarner Losh if (!obj->on_map) 254*592ffb21SWarner Losh return; 255*592ffb21SWarner Losh 256*592ffb21SWarner Losh drm_ht_remove_item(&mm->offset_hash, list); 257*592ffb21SWarner Losh free_unr(mm->idxunr, list->key); 258*592ffb21SWarner Losh obj->on_map = false; 259*592ffb21SWarner Losh } 260*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_free_mmap_offset); 261*592ffb21SWarner Losh 262*592ffb21SWarner Losh int 263*592ffb21SWarner Losh drm_gem_create_mmap_offset(struct drm_gem_object *obj) 264*592ffb21SWarner Losh { 265*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 266*592ffb21SWarner Losh struct drm_gem_mm *mm = dev->mm_private; 267*592ffb21SWarner Losh int ret; 268*592ffb21SWarner Losh 269*592ffb21SWarner Losh if (obj->on_map) 270*592ffb21SWarner Losh return 0; 271*592ffb21SWarner Losh 272*592ffb21SWarner Losh obj->map_list.key = alloc_unr(mm->idxunr); 273*592ffb21SWarner Losh ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list); 274*592ffb21SWarner Losh if (ret) { 275*592ffb21SWarner Losh DRM_ERROR("failed to add to map hash\n"); 276*592ffb21SWarner Losh free_unr(mm->idxunr, obj->map_list.key); 277*592ffb21SWarner Losh return ret; 278*592ffb21SWarner Losh } 279*592ffb21SWarner Losh obj->on_map = true; 280*592ffb21SWarner Losh 281*592ffb21SWarner Losh return 0; 282*592ffb21SWarner Losh } 283*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_create_mmap_offset); 284*592ffb21SWarner Losh 285*592ffb21SWarner Losh /** Returns a reference to the object named by the handle. */ 286*592ffb21SWarner Losh struct drm_gem_object * 287*592ffb21SWarner Losh drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, 288*592ffb21SWarner Losh u32 handle) 289*592ffb21SWarner Losh { 290*592ffb21SWarner Losh struct drm_gem_object *obj; 291*592ffb21SWarner Losh 292*592ffb21SWarner Losh obj = drm_gem_name_ref(&filp->object_names, handle, 293*592ffb21SWarner Losh (void (*)(void *))drm_gem_object_reference); 294*592ffb21SWarner Losh 295*592ffb21SWarner Losh return obj; 296*592ffb21SWarner Losh } 297*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_lookup); 298*592ffb21SWarner Losh 299*592ffb21SWarner Losh int 300*592ffb21SWarner Losh drm_gem_close_ioctl(struct drm_device *dev, void *data, 301*592ffb21SWarner Losh struct drm_file *file_priv) 302*592ffb21SWarner Losh { 303*592ffb21SWarner Losh struct drm_gem_close *args = data; 304*592ffb21SWarner Losh int ret; 305*592ffb21SWarner Losh 306*592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 307*592ffb21SWarner Losh return -ENODEV; 308*592ffb21SWarner Losh 309*592ffb21SWarner Losh ret = drm_gem_handle_delete(file_priv, args->handle); 310*592ffb21SWarner Losh 311*592ffb21SWarner Losh return ret; 312*592ffb21SWarner Losh } 313*592ffb21SWarner Losh 314*592ffb21SWarner Losh int 315*592ffb21SWarner Losh drm_gem_flink_ioctl(struct drm_device *dev, void *data, 316*592ffb21SWarner Losh struct drm_file *file_priv) 317*592ffb21SWarner Losh { 318*592ffb21SWarner Losh struct drm_gem_flink *args = data; 319*592ffb21SWarner Losh struct drm_gem_object *obj; 320*592ffb21SWarner Losh int ret; 321*592ffb21SWarner Losh 322*592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 323*592ffb21SWarner Losh return -ENODEV; 324*592ffb21SWarner Losh 325*592ffb21SWarner Losh obj = drm_gem_object_lookup(dev, file_priv, args->handle); 326*592ffb21SWarner Losh if (obj == NULL) 327*592ffb21SWarner Losh return -ENOENT; 328*592ffb21SWarner Losh 329*592ffb21SWarner Losh ret = drm_gem_name_create(&dev->object_names, obj, &obj->name); 330*592ffb21SWarner Losh if (ret != 0) { 331*592ffb21SWarner Losh if (ret == -EALREADY) 332*592ffb21SWarner Losh ret = 0; 333*592ffb21SWarner Losh drm_gem_object_unreference_unlocked(obj); 334*592ffb21SWarner Losh } 335*592ffb21SWarner Losh if (ret == 0) 336*592ffb21SWarner Losh args->name = obj->name; 337*592ffb21SWarner Losh return ret; 338*592ffb21SWarner Losh } 339*592ffb21SWarner Losh 340*592ffb21SWarner Losh int 341*592ffb21SWarner Losh drm_gem_open_ioctl(struct drm_device *dev, void *data, 342*592ffb21SWarner Losh struct drm_file *file_priv) 343*592ffb21SWarner Losh { 344*592ffb21SWarner Losh struct drm_gem_open *args = data; 345*592ffb21SWarner Losh struct drm_gem_object *obj; 346*592ffb21SWarner Losh int ret; 347*592ffb21SWarner Losh u32 handle; 348*592ffb21SWarner Losh 349*592ffb21SWarner Losh if (!(dev->driver->driver_features & DRIVER_GEM)) 350*592ffb21SWarner Losh return -ENODEV; 351*592ffb21SWarner Losh 352*592ffb21SWarner Losh obj = drm_gem_name_ref(&dev->object_names, args->name, 353*592ffb21SWarner Losh (void (*)(void *))drm_gem_object_reference); 354*592ffb21SWarner Losh if (!obj) 355*592ffb21SWarner Losh return -ENOENT; 356*592ffb21SWarner Losh 357*592ffb21SWarner Losh ret = drm_gem_handle_create(file_priv, obj, &handle); 358*592ffb21SWarner Losh drm_gem_object_unreference_unlocked(obj); 359*592ffb21SWarner Losh if (ret) 360*592ffb21SWarner Losh return ret; 361*592ffb21SWarner Losh 362*592ffb21SWarner Losh args->handle = handle; 363*592ffb21SWarner Losh args->size = obj->size; 364*592ffb21SWarner Losh 365*592ffb21SWarner Losh return 0; 366*592ffb21SWarner Losh } 367*592ffb21SWarner Losh 368*592ffb21SWarner Losh void 369*592ffb21SWarner Losh drm_gem_open(struct drm_device *dev, struct drm_file *file_private) 370*592ffb21SWarner Losh { 371*592ffb21SWarner Losh 372*592ffb21SWarner Losh drm_gem_names_init(&file_private->object_names); 373*592ffb21SWarner Losh } 374*592ffb21SWarner Losh 375*592ffb21SWarner Losh static int 376*592ffb21SWarner Losh drm_gem_object_release_handle(uint32_t name, void *ptr, void *data) 377*592ffb21SWarner Losh { 378*592ffb21SWarner Losh struct drm_file *file_priv = data; 379*592ffb21SWarner Losh struct drm_gem_object *obj = ptr; 380*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 381*592ffb21SWarner Losh 382*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET) 383*592ffb21SWarner Losh drm_gem_remove_prime_handles(obj, file_priv); 384*592ffb21SWarner Losh #endif 385*592ffb21SWarner Losh 386*592ffb21SWarner Losh if (dev->driver->gem_close_object) 387*592ffb21SWarner Losh dev->driver->gem_close_object(obj, file_priv); 388*592ffb21SWarner Losh 389*592ffb21SWarner Losh drm_gem_object_handle_unreference_unlocked(obj); 390*592ffb21SWarner Losh 391*592ffb21SWarner Losh return 0; 392*592ffb21SWarner Losh } 393*592ffb21SWarner Losh 394*592ffb21SWarner Losh void 395*592ffb21SWarner Losh drm_gem_release(struct drm_device *dev, struct drm_file *file_private) 396*592ffb21SWarner Losh { 397*592ffb21SWarner Losh drm_gem_names_foreach(&file_private->object_names, 398*592ffb21SWarner Losh drm_gem_object_release_handle, file_private); 399*592ffb21SWarner Losh 400*592ffb21SWarner Losh drm_gem_names_fini(&file_private->object_names); 401*592ffb21SWarner Losh } 402*592ffb21SWarner Losh 403*592ffb21SWarner Losh void 404*592ffb21SWarner Losh drm_gem_object_release(struct drm_gem_object *obj) 405*592ffb21SWarner Losh { 406*592ffb21SWarner Losh 407*592ffb21SWarner Losh /* 408*592ffb21SWarner Losh * obj->vm_obj can be NULL for private gem objects. 409*592ffb21SWarner Losh */ 410*592ffb21SWarner Losh vm_object_deallocate(obj->vm_obj); 411*592ffb21SWarner Losh } 412*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_release); 413*592ffb21SWarner Losh 414*592ffb21SWarner Losh void 415*592ffb21SWarner Losh drm_gem_object_free(struct drm_gem_object *obj) 416*592ffb21SWarner Losh { 417*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 418*592ffb21SWarner Losh 419*592ffb21SWarner Losh DRM_LOCK_ASSERT(dev); 420*592ffb21SWarner Losh if (dev->driver->gem_free_object != NULL) 421*592ffb21SWarner Losh dev->driver->gem_free_object(obj); 422*592ffb21SWarner Losh } 423*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_free); 424*592ffb21SWarner Losh 425*592ffb21SWarner Losh void drm_gem_object_handle_free(struct drm_gem_object *obj) 426*592ffb21SWarner Losh { 427*592ffb21SWarner Losh struct drm_device *dev = obj->dev; 428*592ffb21SWarner Losh struct drm_gem_object *obj1; 429*592ffb21SWarner Losh 430*592ffb21SWarner Losh if (obj->name) { 431*592ffb21SWarner Losh obj1 = drm_gem_names_remove(&dev->object_names, obj->name); 432*592ffb21SWarner Losh obj->name = 0; 433*592ffb21SWarner Losh drm_gem_object_unreference(obj1); 434*592ffb21SWarner Losh } 435*592ffb21SWarner Losh } 436*592ffb21SWarner Losh 437*592ffb21SWarner Losh static struct drm_gem_object * 438*592ffb21SWarner Losh drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset) 439*592ffb21SWarner Losh { 440*592ffb21SWarner Losh struct drm_gem_object *obj; 441*592ffb21SWarner Losh struct drm_gem_mm *mm; 442*592ffb21SWarner Losh struct drm_hash_item *map_list; 443*592ffb21SWarner Losh 444*592ffb21SWarner Losh if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY) 445*592ffb21SWarner Losh return (NULL); 446*592ffb21SWarner Losh offset &= ~DRM_GEM_MAPPING_KEY; 447*592ffb21SWarner Losh mm = dev->mm_private; 448*592ffb21SWarner Losh if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset), 449*592ffb21SWarner Losh &map_list) != 0) { 450*592ffb21SWarner Losh DRM_DEBUG("drm_gem_object_from_offset: offset 0x%jx obj not found\n", 451*592ffb21SWarner Losh (uintmax_t)offset); 452*592ffb21SWarner Losh return (NULL); 453*592ffb21SWarner Losh } 454*592ffb21SWarner Losh obj = __containerof(map_list, struct drm_gem_object, map_list); 455*592ffb21SWarner Losh return (obj); 456*592ffb21SWarner Losh } 457*592ffb21SWarner Losh 458*592ffb21SWarner Losh int 459*592ffb21SWarner Losh drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size, 460*592ffb21SWarner Losh struct vm_object **obj_res, int nprot) 461*592ffb21SWarner Losh { 462*592ffb21SWarner Losh struct drm_gem_object *gem_obj; 463*592ffb21SWarner Losh struct vm_object *vm_obj; 464*592ffb21SWarner Losh 465*592ffb21SWarner Losh DRM_LOCK(dev); 466*592ffb21SWarner Losh gem_obj = drm_gem_object_from_offset(dev, *offset); 467*592ffb21SWarner Losh if (gem_obj == NULL) { 468*592ffb21SWarner Losh DRM_UNLOCK(dev); 469*592ffb21SWarner Losh return (-ENODEV); 470*592ffb21SWarner Losh } 471*592ffb21SWarner Losh drm_gem_object_reference(gem_obj); 472*592ffb21SWarner Losh DRM_UNLOCK(dev); 473*592ffb21SWarner Losh vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE, 474*592ffb21SWarner Losh dev->driver->gem_pager_ops, size, nprot, 475*592ffb21SWarner Losh DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred); 476*592ffb21SWarner Losh if (vm_obj == NULL) { 477*592ffb21SWarner Losh drm_gem_object_unreference_unlocked(gem_obj); 478*592ffb21SWarner Losh return (-EINVAL); 479*592ffb21SWarner Losh } 480*592ffb21SWarner Losh *offset = DRM_GEM_MAPPING_MAPOFF(*offset); 481*592ffb21SWarner Losh *obj_res = vm_obj; 482*592ffb21SWarner Losh return (0); 483*592ffb21SWarner Losh } 484*592ffb21SWarner Losh 485*592ffb21SWarner Losh void 486*592ffb21SWarner Losh drm_gem_pager_dtr(void *handle) 487*592ffb21SWarner Losh { 488*592ffb21SWarner Losh struct drm_gem_object *obj; 489*592ffb21SWarner Losh struct drm_device *dev; 490*592ffb21SWarner Losh 491*592ffb21SWarner Losh obj = handle; 492*592ffb21SWarner Losh dev = obj->dev; 493*592ffb21SWarner Losh 494*592ffb21SWarner Losh DRM_LOCK(dev); 495*592ffb21SWarner Losh drm_gem_free_mmap_offset(obj); 496*592ffb21SWarner Losh drm_gem_object_unreference(obj); 497*592ffb21SWarner Losh DRM_UNLOCK(dev); 498*592ffb21SWarner Losh } 499