734 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2015-2018 Etnaviv Project4 */5 6#include <drm/drm_prime.h>7#include <linux/dma-mapping.h>8#include <linux/shmem_fs.h>9#include <linux/spinlock.h>10#include <linux/vmalloc.h>11 12#include "etnaviv_drv.h"13#include "etnaviv_gem.h"14#include "etnaviv_gpu.h"15#include "etnaviv_mmu.h"16 17static struct lock_class_key etnaviv_shm_lock_class;18static struct lock_class_key etnaviv_userptr_lock_class;19 20static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)21{22 struct drm_device *dev = etnaviv_obj->base.dev;23 struct sg_table *sgt = etnaviv_obj->sgt;24 25 /*26 * For non-cached buffers, ensure the new pages are clean27 * because display controller, GPU, etc. are not coherent.28 */29 if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)30 dma_map_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);31}32 33static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)34{35 struct drm_device *dev = etnaviv_obj->base.dev;36 struct sg_table *sgt = etnaviv_obj->sgt;37 38 /*39 * For non-cached buffers, ensure the new pages are clean40 * because display controller, GPU, etc. are not coherent:41 *42 * WARNING: The DMA API does not support concurrent CPU43 * and device access to the memory area. With BIDIRECTIONAL,44 * we will clean the cache lines which overlap the region,45 * and invalidate all cache lines (partially) contained in46 * the region.47 *48 * If you have dirty data in the overlapping cache lines,49 * that will corrupt the GPU-written data. If you have50 * written into the remainder of the region, this can51 * discard those writes.52 */53 if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)54 dma_unmap_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);55}56 57/* called with etnaviv_obj->lock held */58static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object *etnaviv_obj)59{60 struct drm_device *dev = etnaviv_obj->base.dev;61 struct page **p = drm_gem_get_pages(&etnaviv_obj->base);62 63 if (IS_ERR(p)) {64 dev_dbg(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));65 return PTR_ERR(p);66 }67 68 etnaviv_obj->pages = p;69 70 return 0;71}72 73static void put_pages(struct etnaviv_gem_object *etnaviv_obj)74{75 if (etnaviv_obj->sgt) {76 etnaviv_gem_scatterlist_unmap(etnaviv_obj);77 sg_free_table(etnaviv_obj->sgt);78 kfree(etnaviv_obj->sgt);79 etnaviv_obj->sgt = NULL;80 }81 if (etnaviv_obj->pages) {82 drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages,83 true, false);84 85 etnaviv_obj->pages = NULL;86 }87}88 89struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)90{91 int ret;92 93 lockdep_assert_held(&etnaviv_obj->lock);94 95 if (!etnaviv_obj->pages) {96 ret = etnaviv_obj->ops->get_pages(etnaviv_obj);97 if (ret < 0)98 return ERR_PTR(ret);99 }100 101 if (!etnaviv_obj->sgt) {102 struct drm_device *dev = etnaviv_obj->base.dev;103 unsigned int npages = etnaviv_obj->base.size >> PAGE_SHIFT;104 struct sg_table *sgt;105 106 sgt = drm_prime_pages_to_sg(dev, etnaviv_obj->pages, npages);107 if (IS_ERR(sgt)) {108 dev_err(dev->dev, "failed to allocate sgt: %ld\n",109 PTR_ERR(sgt));110 return ERR_CAST(sgt);111 }112 113 etnaviv_obj->sgt = sgt;114 115 etnaviv_gem_scatter_map(etnaviv_obj);116 }117 118 return etnaviv_obj->pages;119}120 121void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)122{123 lockdep_assert_held(&etnaviv_obj->lock);124 /* when we start tracking the pin count, then do something here */125}126 127static int etnaviv_gem_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,128 struct vm_area_struct *vma)129{130 pgprot_t vm_page_prot;131 132 vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);133 134 vm_page_prot = vm_get_page_prot(vma->vm_flags);135 136 if (etnaviv_obj->flags & ETNA_BO_WC) {137 vma->vm_page_prot = pgprot_writecombine(vm_page_prot);138 } else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) {139 vma->vm_page_prot = pgprot_noncached(vm_page_prot);140 } else {141 /*142 * Shunt off cached objs to shmem file so they have their own143 * address_space (so unmap_mapping_range does what we want,144 * in particular in the case of mmap'd dmabufs)145 */146 vma->vm_pgoff = 0;147 vma_set_file(vma, etnaviv_obj->base.filp);148 149 vma->vm_page_prot = vm_page_prot;150 }151 152 return 0;153}154 155static int etnaviv_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)156{157 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);158 159 return etnaviv_obj->ops->mmap(etnaviv_obj, vma);160}161 162static vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf)163{164 struct vm_area_struct *vma = vmf->vma;165 struct drm_gem_object *obj = vma->vm_private_data;166 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);167 struct page **pages;168 unsigned long pfn;169 pgoff_t pgoff;170 int err;171 172 /*173 * Make sure we don't parallel update on a fault, nor move or remove174 * something from beneath our feet. Note that vmf_insert_page() is175 * specifically coded to take care of this, so we don't have to.176 */177 err = mutex_lock_interruptible(&etnaviv_obj->lock);178 if (err)179 return VM_FAULT_NOPAGE;180 /* make sure we have pages attached now */181 pages = etnaviv_gem_get_pages(etnaviv_obj);182 mutex_unlock(&etnaviv_obj->lock);183 184 if (IS_ERR(pages)) {185 err = PTR_ERR(pages);186 return vmf_error(err);187 }188 189 /* We don't use vmf->pgoff since that has the fake offset: */190 pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;191 192 pfn = page_to_pfn(pages[pgoff]);193 194 VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address,195 pfn, pfn << PAGE_SHIFT);196 197 return vmf_insert_pfn(vma, vmf->address, pfn);198}199 200int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)201{202 int ret;203 204 /* Make it mmapable */205 ret = drm_gem_create_mmap_offset(obj);206 if (ret)207 dev_err(obj->dev->dev, "could not allocate mmap offset\n");208 else209 *offset = drm_vma_node_offset_addr(&obj->vma_node);210 211 return ret;212}213 214static struct etnaviv_vram_mapping *215etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,216 struct etnaviv_iommu_context *context)217{218 struct etnaviv_vram_mapping *mapping;219 220 list_for_each_entry(mapping, &obj->vram_list, obj_node) {221 if (mapping->context == context)222 return mapping;223 }224 225 return NULL;226}227 228void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping)229{230 struct etnaviv_gem_object *etnaviv_obj = mapping->object;231 232 mutex_lock(&etnaviv_obj->lock);233 WARN_ON(mapping->use == 0);234 mapping->use -= 1;235 mutex_unlock(&etnaviv_obj->lock);236 237 drm_gem_object_put(&etnaviv_obj->base);238}239 240struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(241 struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu_context,242 u64 va)243{244 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);245 struct etnaviv_vram_mapping *mapping;246 struct page **pages;247 int ret = 0;248 249 mutex_lock(&etnaviv_obj->lock);250 mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, mmu_context);251 if (mapping) {252 /*253 * Holding the object lock prevents the use count changing254 * beneath us. If the use count is zero, the MMU might be255 * reaping this object, so take the lock and re-check that256 * the MMU owns this mapping to close this race.257 */258 if (mapping->use == 0) {259 mutex_lock(&mmu_context->lock);260 if (mapping->context == mmu_context)261 if (va && mapping->iova != va) {262 etnaviv_iommu_reap_mapping(mapping);263 mapping = NULL;264 } else {265 mapping->use += 1;266 }267 else268 mapping = NULL;269 mutex_unlock(&mmu_context->lock);270 if (mapping)271 goto out;272 } else {273 mapping->use += 1;274 goto out;275 }276 }277 278 pages = etnaviv_gem_get_pages(etnaviv_obj);279 if (IS_ERR(pages)) {280 ret = PTR_ERR(pages);281 goto out;282 }283 284 /*285 * See if we have a reaped vram mapping we can re-use before286 * allocating a fresh mapping.287 */288 mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, NULL);289 if (!mapping) {290 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);291 if (!mapping) {292 ret = -ENOMEM;293 goto out;294 }295 296 INIT_LIST_HEAD(&mapping->scan_node);297 mapping->object = etnaviv_obj;298 } else {299 list_del(&mapping->obj_node);300 }301 302 mapping->use = 1;303 304 ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,305 mmu_context->global->memory_base,306 mapping, va);307 if (ret < 0)308 kfree(mapping);309 else310 list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);311 312out:313 mutex_unlock(&etnaviv_obj->lock);314 315 if (ret)316 return ERR_PTR(ret);317 318 /* Take a reference on the object */319 drm_gem_object_get(obj);320 return mapping;321}322 323void *etnaviv_gem_vmap(struct drm_gem_object *obj)324{325 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);326 327 if (etnaviv_obj->vaddr)328 return etnaviv_obj->vaddr;329 330 mutex_lock(&etnaviv_obj->lock);331 /*332 * Need to check again, as we might have raced with another thread333 * while waiting for the mutex.334 */335 if (!etnaviv_obj->vaddr)336 etnaviv_obj->vaddr = etnaviv_obj->ops->vmap(etnaviv_obj);337 mutex_unlock(&etnaviv_obj->lock);338 339 return etnaviv_obj->vaddr;340}341 342static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj)343{344 struct page **pages;345 346 lockdep_assert_held(&obj->lock);347 348 pages = etnaviv_gem_get_pages(obj);349 if (IS_ERR(pages))350 return NULL;351 352 return vmap(pages, obj->base.size >> PAGE_SHIFT,353 VM_MAP, pgprot_writecombine(PAGE_KERNEL));354}355 356static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)357{358 op &= ETNA_PREP_READ | ETNA_PREP_WRITE;359 360 if (op == ETNA_PREP_READ)361 return DMA_FROM_DEVICE;362 else if (op == ETNA_PREP_WRITE)363 return DMA_TO_DEVICE;364 else365 return DMA_BIDIRECTIONAL;366}367 368int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,369 struct drm_etnaviv_timespec *timeout)370{371 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);372 struct drm_device *dev = obj->dev;373 bool write = !!(op & ETNA_PREP_WRITE);374 int ret;375 376 if (!etnaviv_obj->sgt) {377 void *ret;378 379 mutex_lock(&etnaviv_obj->lock);380 ret = etnaviv_gem_get_pages(etnaviv_obj);381 mutex_unlock(&etnaviv_obj->lock);382 if (IS_ERR(ret))383 return PTR_ERR(ret);384 }385 386 if (op & ETNA_PREP_NOSYNC) {387 if (!dma_resv_test_signaled(obj->resv,388 dma_resv_usage_rw(write)))389 return -EBUSY;390 } else {391 unsigned long remain = etnaviv_timeout_to_jiffies(timeout);392 393 ret = dma_resv_wait_timeout(obj->resv, dma_resv_usage_rw(write),394 true, remain);395 if (ret <= 0)396 return ret == 0 ? -ETIMEDOUT : ret;397 }398 399 if (etnaviv_obj->flags & ETNA_BO_CACHED) {400 dma_sync_sgtable_for_cpu(dev->dev, etnaviv_obj->sgt,401 etnaviv_op_to_dma_dir(op));402 etnaviv_obj->last_cpu_prep_op = op;403 }404 405 return 0;406}407 408int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)409{410 struct drm_device *dev = obj->dev;411 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);412 413 if (etnaviv_obj->flags & ETNA_BO_CACHED) {414 /* fini without a prep is almost certainly a userspace error */415 WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);416 dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,417 etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));418 etnaviv_obj->last_cpu_prep_op = 0;419 }420 421 return 0;422}423 424int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,425 struct drm_etnaviv_timespec *timeout)426{427 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);428 429 return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);430}431 432#ifdef CONFIG_DEBUG_FS433static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)434{435 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);436 struct dma_resv *robj = obj->resv;437 unsigned long off = drm_vma_node_start(&obj->vma_node);438 int r;439 440 seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n",441 etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',442 obj->name, kref_read(&obj->refcount),443 off, etnaviv_obj->vaddr, obj->size);444 445 r = dma_resv_lock(robj, NULL);446 if (r)447 return;448 449 dma_resv_describe(robj, m);450 dma_resv_unlock(robj);451}452 453void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,454 struct seq_file *m)455{456 struct etnaviv_gem_object *etnaviv_obj;457 int count = 0;458 size_t size = 0;459 460 mutex_lock(&priv->gem_lock);461 list_for_each_entry(etnaviv_obj, &priv->gem_list, gem_node) {462 struct drm_gem_object *obj = &etnaviv_obj->base;463 464 seq_puts(m, " ");465 etnaviv_gem_describe(obj, m);466 count++;467 size += obj->size;468 }469 mutex_unlock(&priv->gem_lock);470 471 seq_printf(m, "Total %d objects, %zu bytes\n", count, size);472}473#endif474 475static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)476{477 vunmap(etnaviv_obj->vaddr);478 put_pages(etnaviv_obj);479}480 481static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {482 .get_pages = etnaviv_gem_shmem_get_pages,483 .release = etnaviv_gem_shmem_release,484 .vmap = etnaviv_gem_vmap_impl,485 .mmap = etnaviv_gem_mmap_obj,486};487 488void etnaviv_gem_free_object(struct drm_gem_object *obj)489{490 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);491 struct etnaviv_drm_private *priv = obj->dev->dev_private;492 struct etnaviv_vram_mapping *mapping, *tmp;493 494 /* object should not be active */495 WARN_ON(is_active(etnaviv_obj));496 497 mutex_lock(&priv->gem_lock);498 list_del(&etnaviv_obj->gem_node);499 mutex_unlock(&priv->gem_lock);500 501 list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,502 obj_node) {503 struct etnaviv_iommu_context *context = mapping->context;504 505 WARN_ON(mapping->use);506 507 if (context)508 etnaviv_iommu_unmap_gem(context, mapping);509 510 list_del(&mapping->obj_node);511 kfree(mapping);512 }513 514 etnaviv_obj->ops->release(etnaviv_obj);515 drm_gem_object_release(obj);516 517 kfree(etnaviv_obj);518}519 520void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)521{522 struct etnaviv_drm_private *priv = dev->dev_private;523 struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);524 525 mutex_lock(&priv->gem_lock);526 list_add_tail(&etnaviv_obj->gem_node, &priv->gem_list);527 mutex_unlock(&priv->gem_lock);528}529 530static const struct vm_operations_struct vm_ops = {531 .fault = etnaviv_gem_fault,532 .open = drm_gem_vm_open,533 .close = drm_gem_vm_close,534};535 536static const struct drm_gem_object_funcs etnaviv_gem_object_funcs = {537 .free = etnaviv_gem_free_object,538 .pin = etnaviv_gem_prime_pin,539 .unpin = etnaviv_gem_prime_unpin,540 .get_sg_table = etnaviv_gem_prime_get_sg_table,541 .vmap = etnaviv_gem_prime_vmap,542 .mmap = etnaviv_gem_mmap,543 .vm_ops = &vm_ops,544};545 546static int etnaviv_gem_new_impl(struct drm_device *dev, u32 flags,547 const struct etnaviv_gem_ops *ops, struct drm_gem_object **obj)548{549 struct etnaviv_gem_object *etnaviv_obj;550 unsigned sz = sizeof(*etnaviv_obj);551 bool valid = true;552 553 /* validate flags */554 switch (flags & ETNA_BO_CACHE_MASK) {555 case ETNA_BO_UNCACHED:556 case ETNA_BO_CACHED:557 case ETNA_BO_WC:558 break;559 default:560 valid = false;561 }562 563 if (!valid) {564 dev_err(dev->dev, "invalid cache flag: %x\n",565 (flags & ETNA_BO_CACHE_MASK));566 return -EINVAL;567 }568 569 etnaviv_obj = kzalloc(sz, GFP_KERNEL);570 if (!etnaviv_obj)571 return -ENOMEM;572 573 etnaviv_obj->flags = flags;574 etnaviv_obj->ops = ops;575 576 mutex_init(&etnaviv_obj->lock);577 INIT_LIST_HEAD(&etnaviv_obj->vram_list);578 579 *obj = &etnaviv_obj->base;580 (*obj)->funcs = &etnaviv_gem_object_funcs;581 582 return 0;583}584 585/* convenience method to construct a GEM buffer object, and userspace handle */586int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,587 u32 size, u32 flags, u32 *handle)588{589 struct etnaviv_drm_private *priv = dev->dev_private;590 struct drm_gem_object *obj = NULL;591 int ret;592 593 size = PAGE_ALIGN(size);594 595 ret = etnaviv_gem_new_impl(dev, flags, &etnaviv_gem_shmem_ops, &obj);596 if (ret)597 goto fail;598 599 lockdep_set_class(&to_etnaviv_bo(obj)->lock, &etnaviv_shm_lock_class);600 601 ret = drm_gem_object_init(dev, obj, size);602 if (ret)603 goto fail;604 605 /*606 * Our buffers are kept pinned, so allocating them from the MOVABLE607 * zone is a really bad idea, and conflicts with CMA. See comments608 * above new_inode() why this is required _and_ expected if you're609 * going to pin these pages.610 */611 mapping_set_gfp_mask(obj->filp->f_mapping, priv->shm_gfp_mask);612 613 etnaviv_gem_obj_add(dev, obj);614 615 ret = drm_gem_handle_create(file, obj, handle);616 617 /* drop reference from allocate - handle holds it now */618fail:619 drm_gem_object_put(obj);620 621 return ret;622}623 624int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,625 const struct etnaviv_gem_ops *ops, struct etnaviv_gem_object **res)626{627 struct drm_gem_object *obj;628 int ret;629 630 ret = etnaviv_gem_new_impl(dev, flags, ops, &obj);631 if (ret)632 return ret;633 634 drm_gem_private_object_init(dev, obj, size);635 636 *res = to_etnaviv_bo(obj);637 638 return 0;639}640 641static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)642{643 struct page **pvec = NULL;644 struct etnaviv_gem_userptr *userptr = &etnaviv_obj->userptr;645 int ret, pinned = 0, npages = etnaviv_obj->base.size >> PAGE_SHIFT;646 unsigned int gup_flags = FOLL_LONGTERM;647 648 might_lock_read(¤t->mm->mmap_lock);649 650 if (userptr->mm != current->mm)651 return -EPERM;652 653 pvec = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);654 if (!pvec)655 return -ENOMEM;656 657 if (!userptr->ro)658 gup_flags |= FOLL_WRITE;659 660 do {661 unsigned num_pages = npages - pinned;662 uint64_t ptr = userptr->ptr + pinned * PAGE_SIZE;663 struct page **pages = pvec + pinned;664 665 ret = pin_user_pages_fast(ptr, num_pages, gup_flags, pages);666 if (ret < 0) {667 unpin_user_pages(pvec, pinned);668 kvfree(pvec);669 return ret;670 }671 672 pinned += ret;673 674 } while (pinned < npages);675 676 etnaviv_obj->pages = pvec;677 678 return 0;679}680 681static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)682{683 if (etnaviv_obj->sgt) {684 etnaviv_gem_scatterlist_unmap(etnaviv_obj);685 sg_free_table(etnaviv_obj->sgt);686 kfree(etnaviv_obj->sgt);687 }688 if (etnaviv_obj->pages) {689 int npages = etnaviv_obj->base.size >> PAGE_SHIFT;690 691 unpin_user_pages(etnaviv_obj->pages, npages);692 kvfree(etnaviv_obj->pages);693 }694}695 696static int etnaviv_gem_userptr_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,697 struct vm_area_struct *vma)698{699 return -EINVAL;700}701 702static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {703 .get_pages = etnaviv_gem_userptr_get_pages,704 .release = etnaviv_gem_userptr_release,705 .vmap = etnaviv_gem_vmap_impl,706 .mmap = etnaviv_gem_userptr_mmap_obj,707};708 709int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,710 uintptr_t ptr, u32 size, u32 flags, u32 *handle)711{712 struct etnaviv_gem_object *etnaviv_obj;713 int ret;714 715 ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED,716 &etnaviv_gem_userptr_ops, &etnaviv_obj);717 if (ret)718 return ret;719 720 lockdep_set_class(&etnaviv_obj->lock, &etnaviv_userptr_lock_class);721 722 etnaviv_obj->userptr.ptr = ptr;723 etnaviv_obj->userptr.mm = current->mm;724 etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);725 726 etnaviv_gem_obj_add(dev, &etnaviv_obj->base);727 728 ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);729 730 /* drop reference from allocate - handle holds it now */731 drm_gem_object_put(&etnaviv_obj->base);732 return ret;733}734