brintos

brintos / linux-shallow public Read only

0
0
Text · 18.1 KiB · 5c0c9d4 Raw
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(&current->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