brintos

brintos / linux-shallow public Read only

0
0
Text · 20.2 KiB · 53c0039 Raw
783 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2018 Noralf Trønnes4 */5 6#include <linux/dma-buf.h>7#include <linux/export.h>8#include <linux/module.h>9#include <linux/mutex.h>10#include <linux/shmem_fs.h>11#include <linux/slab.h>12#include <linux/vmalloc.h>13 14#ifdef CONFIG_X8615#include <asm/set_memory.h>16#endif17 18#include <drm/drm.h>19#include <drm/drm_device.h>20#include <drm/drm_drv.h>21#include <drm/drm_gem_shmem_helper.h>22#include <drm/drm_prime.h>23#include <drm/drm_print.h>24 25MODULE_IMPORT_NS(DMA_BUF);26 27/**28 * DOC: overview29 *30 * This library provides helpers for GEM objects backed by shmem buffers31 * allocated using anonymous pageable memory.32 *33 * Functions that operate on the GEM object receive struct &drm_gem_shmem_object.34 * For GEM callback helpers in struct &drm_gem_object functions, see likewise35 * named functions with an _object_ infix (e.g., drm_gem_shmem_object_vmap() wraps36 * drm_gem_shmem_vmap()). These helpers perform the necessary type conversion.37 */38 39static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {40	.free = drm_gem_shmem_object_free,41	.print_info = drm_gem_shmem_object_print_info,42	.pin = drm_gem_shmem_object_pin,43	.unpin = drm_gem_shmem_object_unpin,44	.get_sg_table = drm_gem_shmem_object_get_sg_table,45	.vmap = drm_gem_shmem_object_vmap,46	.vunmap = drm_gem_shmem_object_vunmap,47	.mmap = drm_gem_shmem_object_mmap,48	.vm_ops = &drm_gem_shmem_vm_ops,49};50 51static struct drm_gem_shmem_object *52__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)53{54	struct drm_gem_shmem_object *shmem;55	struct drm_gem_object *obj;56	int ret = 0;57 58	size = PAGE_ALIGN(size);59 60	if (dev->driver->gem_create_object) {61		obj = dev->driver->gem_create_object(dev, size);62		if (IS_ERR(obj))63			return ERR_CAST(obj);64		shmem = to_drm_gem_shmem_obj(obj);65	} else {66		shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);67		if (!shmem)68			return ERR_PTR(-ENOMEM);69		obj = &shmem->base;70	}71 72	if (!obj->funcs)73		obj->funcs = &drm_gem_shmem_funcs;74 75	if (private) {76		drm_gem_private_object_init(dev, obj, size);77		shmem->map_wc = false; /* dma-buf mappings use always writecombine */78	} else {79		ret = drm_gem_object_init(dev, obj, size);80	}81	if (ret) {82		drm_gem_private_object_fini(obj);83		goto err_free;84	}85 86	ret = drm_gem_create_mmap_offset(obj);87	if (ret)88		goto err_release;89 90	INIT_LIST_HEAD(&shmem->madv_list);91 92	if (!private) {93		/*94		 * Our buffers are kept pinned, so allocating them95		 * from the MOVABLE zone is a really bad idea, and96		 * conflicts with CMA. See comments above new_inode()97		 * why this is required _and_ expected if you're98		 * going to pin these pages.99		 */100		mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER |101				     __GFP_RETRY_MAYFAIL | __GFP_NOWARN);102	}103 104	return shmem;105 106err_release:107	drm_gem_object_release(obj);108err_free:109	kfree(obj);110 111	return ERR_PTR(ret);112}113/**114 * drm_gem_shmem_create - Allocate an object with the given size115 * @dev: DRM device116 * @size: Size of the object to allocate117 *118 * This function creates a shmem GEM object.119 *120 * Returns:121 * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative122 * error code on failure.123 */124struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)125{126	return __drm_gem_shmem_create(dev, size, false);127}128EXPORT_SYMBOL_GPL(drm_gem_shmem_create);129 130/**131 * drm_gem_shmem_free - Free resources associated with a shmem GEM object132 * @shmem: shmem GEM object to free133 *134 * This function cleans up the GEM object state and frees the memory used to135 * store the object itself.136 */137void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)138{139	struct drm_gem_object *obj = &shmem->base;140 141	if (obj->import_attach) {142		drm_prime_gem_destroy(obj, shmem->sgt);143	} else {144		dma_resv_lock(shmem->base.resv, NULL);145 146		drm_WARN_ON(obj->dev, shmem->vmap_use_count);147 148		if (shmem->sgt) {149			dma_unmap_sgtable(obj->dev->dev, shmem->sgt,150					  DMA_BIDIRECTIONAL, 0);151			sg_free_table(shmem->sgt);152			kfree(shmem->sgt);153		}154		if (shmem->pages)155			drm_gem_shmem_put_pages(shmem);156 157		drm_WARN_ON(obj->dev, shmem->pages_use_count);158 159		dma_resv_unlock(shmem->base.resv);160	}161 162	drm_gem_object_release(obj);163	kfree(shmem);164}165EXPORT_SYMBOL_GPL(drm_gem_shmem_free);166 167static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)168{169	struct drm_gem_object *obj = &shmem->base;170	struct page **pages;171 172	dma_resv_assert_held(shmem->base.resv);173 174	if (shmem->pages_use_count++ > 0)175		return 0;176 177	pages = drm_gem_get_pages(obj);178	if (IS_ERR(pages)) {179		drm_dbg_kms(obj->dev, "Failed to get pages (%ld)\n",180			    PTR_ERR(pages));181		shmem->pages_use_count = 0;182		return PTR_ERR(pages);183	}184 185	/*186	 * TODO: Allocating WC pages which are correctly flushed is only187	 * supported on x86. Ideal solution would be a GFP_WC flag, which also188	 * ttm_pool.c could use.189	 */190#ifdef CONFIG_X86191	if (shmem->map_wc)192		set_pages_array_wc(pages, obj->size >> PAGE_SHIFT);193#endif194 195	shmem->pages = pages;196 197	return 0;198}199 200/*201 * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object202 * @shmem: shmem GEM object203 *204 * This function decreases the use count and puts the backing pages when use drops to zero.205 */206void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)207{208	struct drm_gem_object *obj = &shmem->base;209 210	dma_resv_assert_held(shmem->base.resv);211 212	if (drm_WARN_ON_ONCE(obj->dev, !shmem->pages_use_count))213		return;214 215	if (--shmem->pages_use_count > 0)216		return;217 218#ifdef CONFIG_X86219	if (shmem->map_wc)220		set_pages_array_wb(shmem->pages, obj->size >> PAGE_SHIFT);221#endif222 223	drm_gem_put_pages(obj, shmem->pages,224			  shmem->pages_mark_dirty_on_put,225			  shmem->pages_mark_accessed_on_put);226	shmem->pages = NULL;227}228EXPORT_SYMBOL(drm_gem_shmem_put_pages);229 230int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)231{232	int ret;233 234	dma_resv_assert_held(shmem->base.resv);235 236	drm_WARN_ON(shmem->base.dev, shmem->base.import_attach);237 238	ret = drm_gem_shmem_get_pages(shmem);239 240	return ret;241}242EXPORT_SYMBOL(drm_gem_shmem_pin_locked);243 244void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)245{246	dma_resv_assert_held(shmem->base.resv);247 248	drm_gem_shmem_put_pages(shmem);249}250EXPORT_SYMBOL(drm_gem_shmem_unpin_locked);251 252/**253 * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object254 * @shmem: shmem GEM object255 *256 * This function makes sure the backing pages are pinned in memory while the257 * buffer is exported.258 *259 * Returns:260 * 0 on success or a negative error code on failure.261 */262int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)263{264	struct drm_gem_object *obj = &shmem->base;265	int ret;266 267	drm_WARN_ON(obj->dev, obj->import_attach);268 269	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);270	if (ret)271		return ret;272	ret = drm_gem_shmem_pin_locked(shmem);273	dma_resv_unlock(shmem->base.resv);274 275	return ret;276}277EXPORT_SYMBOL(drm_gem_shmem_pin);278 279/**280 * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object281 * @shmem: shmem GEM object282 *283 * This function removes the requirement that the backing pages are pinned in284 * memory.285 */286void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)287{288	struct drm_gem_object *obj = &shmem->base;289 290	drm_WARN_ON(obj->dev, obj->import_attach);291 292	dma_resv_lock(shmem->base.resv, NULL);293	drm_gem_shmem_unpin_locked(shmem);294	dma_resv_unlock(shmem->base.resv);295}296EXPORT_SYMBOL(drm_gem_shmem_unpin);297 298/*299 * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object300 * @shmem: shmem GEM object301 * @map: Returns the kernel virtual address of the SHMEM GEM object's backing302 *       store.303 *304 * This function makes sure that a contiguous kernel virtual address mapping305 * exists for the buffer backing the shmem GEM object. It hides the differences306 * between dma-buf imported and natively allocated objects.307 *308 * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap().309 *310 * Returns:311 * 0 on success or a negative error code on failure.312 */313int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,314		       struct iosys_map *map)315{316	struct drm_gem_object *obj = &shmem->base;317	int ret = 0;318 319	if (obj->import_attach) {320		ret = dma_buf_vmap(obj->import_attach->dmabuf, map);321		if (!ret) {322			if (drm_WARN_ON(obj->dev, map->is_iomem)) {323				dma_buf_vunmap(obj->import_attach->dmabuf, map);324				return -EIO;325			}326		}327	} else {328		pgprot_t prot = PAGE_KERNEL;329 330		dma_resv_assert_held(shmem->base.resv);331 332		if (shmem->vmap_use_count++ > 0) {333			iosys_map_set_vaddr(map, shmem->vaddr);334			return 0;335		}336 337		ret = drm_gem_shmem_get_pages(shmem);338		if (ret)339			goto err_zero_use;340 341		if (shmem->map_wc)342			prot = pgprot_writecombine(prot);343		shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,344				    VM_MAP, prot);345		if (!shmem->vaddr)346			ret = -ENOMEM;347		else348			iosys_map_set_vaddr(map, shmem->vaddr);349	}350 351	if (ret) {352		drm_dbg_kms(obj->dev, "Failed to vmap pages, error %d\n", ret);353		goto err_put_pages;354	}355 356	return 0;357 358err_put_pages:359	if (!obj->import_attach)360		drm_gem_shmem_put_pages(shmem);361err_zero_use:362	shmem->vmap_use_count = 0;363 364	return ret;365}366EXPORT_SYMBOL(drm_gem_shmem_vmap);367 368/*369 * drm_gem_shmem_vunmap - Unmap a virtual mapping for a shmem GEM object370 * @shmem: shmem GEM object371 * @map: Kernel virtual address where the SHMEM GEM object was mapped372 *373 * This function cleans up a kernel virtual address mapping acquired by374 * drm_gem_shmem_vmap(). The mapping is only removed when the use count drops to375 * zero.376 *377 * This function hides the differences between dma-buf imported and natively378 * allocated objects.379 */380void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,381			  struct iosys_map *map)382{383	struct drm_gem_object *obj = &shmem->base;384 385	if (obj->import_attach) {386		dma_buf_vunmap(obj->import_attach->dmabuf, map);387	} else {388		dma_resv_assert_held(shmem->base.resv);389 390		if (drm_WARN_ON_ONCE(obj->dev, !shmem->vmap_use_count))391			return;392 393		if (--shmem->vmap_use_count > 0)394			return;395 396		vunmap(shmem->vaddr);397		drm_gem_shmem_put_pages(shmem);398	}399 400	shmem->vaddr = NULL;401}402EXPORT_SYMBOL(drm_gem_shmem_vunmap);403 404static int405drm_gem_shmem_create_with_handle(struct drm_file *file_priv,406				 struct drm_device *dev, size_t size,407				 uint32_t *handle)408{409	struct drm_gem_shmem_object *shmem;410	int ret;411 412	shmem = drm_gem_shmem_create(dev, size);413	if (IS_ERR(shmem))414		return PTR_ERR(shmem);415 416	/*417	 * Allocate an id of idr table where the obj is registered418	 * and handle has the id what user can see.419	 */420	ret = drm_gem_handle_create(file_priv, &shmem->base, handle);421	/* drop reference from allocate - handle holds it now. */422	drm_gem_object_put(&shmem->base);423 424	return ret;425}426 427/* Update madvise status, returns true if not purged, else428 * false or -errno.429 */430int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)431{432	dma_resv_assert_held(shmem->base.resv);433 434	if (shmem->madv >= 0)435		shmem->madv = madv;436 437	madv = shmem->madv;438 439	return (madv >= 0);440}441EXPORT_SYMBOL(drm_gem_shmem_madvise);442 443void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)444{445	struct drm_gem_object *obj = &shmem->base;446	struct drm_device *dev = obj->dev;447 448	dma_resv_assert_held(shmem->base.resv);449 450	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));451 452	dma_unmap_sgtable(dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);453	sg_free_table(shmem->sgt);454	kfree(shmem->sgt);455	shmem->sgt = NULL;456 457	drm_gem_shmem_put_pages(shmem);458 459	shmem->madv = -1;460 461	drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);462	drm_gem_free_mmap_offset(obj);463 464	/* Our goal here is to return as much of the memory as465	 * is possible back to the system as we are called from OOM.466	 * To do this we must instruct the shmfs to drop all of its467	 * backing pages, *now*.468	 */469	shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1);470 471	invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1);472}473EXPORT_SYMBOL(drm_gem_shmem_purge);474 475/**476 * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object477 * @file: DRM file structure to create the dumb buffer for478 * @dev: DRM device479 * @args: IOCTL data480 *481 * This function computes the pitch of the dumb buffer and rounds it up to an482 * integer number of bytes per pixel. Drivers for hardware that doesn't have483 * any additional restrictions on the pitch can directly use this function as484 * their &drm_driver.dumb_create callback.485 *486 * For hardware with additional restrictions, drivers can adjust the fields487 * set up by userspace before calling into this function.488 *489 * Returns:490 * 0 on success or a negative error code on failure.491 */492int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,493			      struct drm_mode_create_dumb *args)494{495	u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);496 497	if (!args->pitch || !args->size) {498		args->pitch = min_pitch;499		args->size = PAGE_ALIGN(args->pitch * args->height);500	} else {501		/* ensure sane minimum values */502		if (args->pitch < min_pitch)503			args->pitch = min_pitch;504		if (args->size < args->pitch * args->height)505			args->size = PAGE_ALIGN(args->pitch * args->height);506	}507 508	return drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);509}510EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);511 512static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)513{514	struct vm_area_struct *vma = vmf->vma;515	struct drm_gem_object *obj = vma->vm_private_data;516	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);517	loff_t num_pages = obj->size >> PAGE_SHIFT;518	vm_fault_t ret;519	struct page *page;520	pgoff_t page_offset;521 522	/* We don't use vmf->pgoff since that has the fake offset */523	page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;524 525	dma_resv_lock(shmem->base.resv, NULL);526 527	if (page_offset >= num_pages ||528	    drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||529	    shmem->madv < 0) {530		ret = VM_FAULT_SIGBUS;531	} else {532		page = shmem->pages[page_offset];533 534		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));535	}536 537	dma_resv_unlock(shmem->base.resv);538 539	return ret;540}541 542static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)543{544	struct drm_gem_object *obj = vma->vm_private_data;545	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);546 547	drm_WARN_ON(obj->dev, obj->import_attach);548 549	dma_resv_lock(shmem->base.resv, NULL);550 551	/*552	 * We should have already pinned the pages when the buffer was first553	 * mmap'd, vm_open() just grabs an additional reference for the new554	 * mm the vma is getting copied into (ie. on fork()).555	 */556	if (!drm_WARN_ON_ONCE(obj->dev, !shmem->pages_use_count))557		shmem->pages_use_count++;558 559	dma_resv_unlock(shmem->base.resv);560 561	drm_gem_vm_open(vma);562}563 564static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)565{566	struct drm_gem_object *obj = vma->vm_private_data;567	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);568 569	dma_resv_lock(shmem->base.resv, NULL);570	drm_gem_shmem_put_pages(shmem);571	dma_resv_unlock(shmem->base.resv);572 573	drm_gem_vm_close(vma);574}575 576const struct vm_operations_struct drm_gem_shmem_vm_ops = {577	.fault = drm_gem_shmem_fault,578	.open = drm_gem_shmem_vm_open,579	.close = drm_gem_shmem_vm_close,580};581EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);582 583/**584 * drm_gem_shmem_mmap - Memory-map a shmem GEM object585 * @shmem: shmem GEM object586 * @vma: VMA for the area to be mapped587 *588 * This function implements an augmented version of the GEM DRM file mmap589 * operation for shmem objects.590 *591 * Returns:592 * 0 on success or a negative error code on failure.593 */594int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma)595{596	struct drm_gem_object *obj = &shmem->base;597	int ret;598 599	if (obj->import_attach) {600		/* Reset both vm_ops and vm_private_data, so we don't end up with601		 * vm_ops pointing to our implementation if the dma-buf backend602		 * doesn't set those fields.603		 */604		vma->vm_private_data = NULL;605		vma->vm_ops = NULL;606 607		ret = dma_buf_mmap(obj->dma_buf, vma, 0);608 609		/* Drop the reference drm_gem_mmap_obj() acquired.*/610		if (!ret)611			drm_gem_object_put(obj);612 613		return ret;614	}615 616	if (is_cow_mapping(vma->vm_flags))617		return -EINVAL;618 619	dma_resv_lock(shmem->base.resv, NULL);620	ret = drm_gem_shmem_get_pages(shmem);621	dma_resv_unlock(shmem->base.resv);622 623	if (ret)624		return ret;625 626	vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);627	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);628	if (shmem->map_wc)629		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);630 631	return 0;632}633EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);634 635/**636 * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs637 * @shmem: shmem GEM object638 * @p: DRM printer639 * @indent: Tab indentation level640 */641void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,642			      struct drm_printer *p, unsigned int indent)643{644	if (shmem->base.import_attach)645		return;646 647	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);648	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);649	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);650}651EXPORT_SYMBOL(drm_gem_shmem_print_info);652 653/**654 * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned655 *                              pages for a shmem GEM object656 * @shmem: shmem GEM object657 *658 * This function exports a scatter/gather table suitable for PRIME usage by659 * calling the standard DMA mapping API.660 *661 * Drivers who need to acquire an scatter/gather table for objects need to call662 * drm_gem_shmem_get_pages_sgt() instead.663 *664 * Returns:665 * A pointer to the scatter/gather table of pinned pages or error pointer on failure.666 */667struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem)668{669	struct drm_gem_object *obj = &shmem->base;670 671	drm_WARN_ON(obj->dev, obj->import_attach);672 673	return drm_prime_pages_to_sg(obj->dev, shmem->pages, obj->size >> PAGE_SHIFT);674}675EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);676 677static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem)678{679	struct drm_gem_object *obj = &shmem->base;680	int ret;681	struct sg_table *sgt;682 683	if (shmem->sgt)684		return shmem->sgt;685 686	drm_WARN_ON(obj->dev, obj->import_attach);687 688	ret = drm_gem_shmem_get_pages(shmem);689	if (ret)690		return ERR_PTR(ret);691 692	sgt = drm_gem_shmem_get_sg_table(shmem);693	if (IS_ERR(sgt)) {694		ret = PTR_ERR(sgt);695		goto err_put_pages;696	}697	/* Map the pages for use by the h/w. */698	ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0);699	if (ret)700		goto err_free_sgt;701 702	shmem->sgt = sgt;703 704	return sgt;705 706err_free_sgt:707	sg_free_table(sgt);708	kfree(sgt);709err_put_pages:710	drm_gem_shmem_put_pages(shmem);711	return ERR_PTR(ret);712}713 714/**715 * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a716 *				 scatter/gather table for a shmem GEM object.717 * @shmem: shmem GEM object718 *719 * This function returns a scatter/gather table suitable for driver usage. If720 * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg721 * table created.722 *723 * This is the main function for drivers to get at backing storage, and it hides724 * and difference between dma-buf imported and natively allocated objects.725 * drm_gem_shmem_get_sg_table() should not be directly called by drivers.726 *727 * Returns:728 * A pointer to the scatter/gather table of pinned pages or errno on failure.729 */730struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)731{732	int ret;733	struct sg_table *sgt;734 735	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);736	if (ret)737		return ERR_PTR(ret);738	sgt = drm_gem_shmem_get_pages_sgt_locked(shmem);739	dma_resv_unlock(shmem->base.resv);740 741	return sgt;742}743EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt);744 745/**746 * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from747 *                 another driver's scatter/gather table of pinned pages748 * @dev: Device to import into749 * @attach: DMA-BUF attachment750 * @sgt: Scatter/gather table of pinned pages751 *752 * This function imports a scatter/gather table exported via DMA-BUF by753 * another driver. Drivers that use the shmem helpers should set this as their754 * &drm_driver.gem_prime_import_sg_table callback.755 *756 * Returns:757 * A pointer to a newly created GEM object or an ERR_PTR-encoded negative758 * error code on failure.759 */760struct drm_gem_object *761drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,762				    struct dma_buf_attachment *attach,763				    struct sg_table *sgt)764{765	size_t size = PAGE_ALIGN(attach->dmabuf->size);766	struct drm_gem_shmem_object *shmem;767 768	shmem = __drm_gem_shmem_create(dev, size, true);769	if (IS_ERR(shmem))770		return ERR_CAST(shmem);771 772	shmem->sgt = sgt;773 774	drm_dbg_prime(dev, "size = %zu\n", size);775 776	return &shmem->base;777}778EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);779 780MODULE_DESCRIPTION("DRM SHMEM memory-management helpers");781MODULE_IMPORT_NS(DMA_BUF);782MODULE_LICENSE("GPL v2");783