162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drm gem DMA helper functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Sascha Hauer, Pengutronix
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Based on Samsung Exynos code
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/dma-buf.h>
1362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1462306a36Sopenharmony_ci#include <linux/export.h>
1562306a36Sopenharmony_ci#include <linux/mm.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/mutex.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <drm/drm.h>
2162306a36Sopenharmony_ci#include <drm/drm_device.h>
2262306a36Sopenharmony_ci#include <drm/drm_drv.h>
2362306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h>
2462306a36Sopenharmony_ci#include <drm/drm_vma_manager.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/**
2762306a36Sopenharmony_ci * DOC: dma helpers
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * The DRM GEM/DMA helpers are a means to provide buffer objects that are
3062306a36Sopenharmony_ci * presented to the device as a contiguous chunk of memory. This is useful
3162306a36Sopenharmony_ci * for devices that do not support scatter-gather DMA (either directly or
3262306a36Sopenharmony_ci * by using an intimately attached IOMMU).
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * For devices that access the memory bus through an (external) IOMMU then
3562306a36Sopenharmony_ci * the buffer objects are allocated using a traditional page-based
3662306a36Sopenharmony_ci * allocator and may be scattered through physical memory. However they
3762306a36Sopenharmony_ci * are contiguous in the IOVA space so appear contiguous to devices using
3862306a36Sopenharmony_ci * them.
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * For other devices then the helpers rely on CMA to provide buffer
4162306a36Sopenharmony_ci * objects that are physically contiguous in memory.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * For GEM callback helpers in struct &drm_gem_object functions, see likewise
4462306a36Sopenharmony_ci * named functions with an _object_ infix (e.g., drm_gem_dma_object_vmap() wraps
4562306a36Sopenharmony_ci * drm_gem_dma_vmap()). These helpers perform the necessary type conversion.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic const struct drm_gem_object_funcs drm_gem_dma_default_funcs = {
4962306a36Sopenharmony_ci	.free = drm_gem_dma_object_free,
5062306a36Sopenharmony_ci	.print_info = drm_gem_dma_object_print_info,
5162306a36Sopenharmony_ci	.get_sg_table = drm_gem_dma_object_get_sg_table,
5262306a36Sopenharmony_ci	.vmap = drm_gem_dma_object_vmap,
5362306a36Sopenharmony_ci	.mmap = drm_gem_dma_object_mmap,
5462306a36Sopenharmony_ci	.vm_ops = &drm_gem_dma_vm_ops,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/**
5862306a36Sopenharmony_ci * __drm_gem_dma_create - Create a GEM DMA object without allocating memory
5962306a36Sopenharmony_ci * @drm: DRM device
6062306a36Sopenharmony_ci * @size: size of the object to allocate
6162306a36Sopenharmony_ci * @private: true if used for internal purposes
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * This function creates and initializes a GEM DMA object of the given size,
6462306a36Sopenharmony_ci * but doesn't allocate any memory to back the object.
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * Returns:
6762306a36Sopenharmony_ci * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative
6862306a36Sopenharmony_ci * error code on failure.
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistatic struct drm_gem_dma_object *
7162306a36Sopenharmony_ci__drm_gem_dma_create(struct drm_device *drm, size_t size, bool private)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
7462306a36Sopenharmony_ci	struct drm_gem_object *gem_obj;
7562306a36Sopenharmony_ci	int ret = 0;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (drm->driver->gem_create_object) {
7862306a36Sopenharmony_ci		gem_obj = drm->driver->gem_create_object(drm, size);
7962306a36Sopenharmony_ci		if (IS_ERR(gem_obj))
8062306a36Sopenharmony_ci			return ERR_CAST(gem_obj);
8162306a36Sopenharmony_ci		dma_obj = to_drm_gem_dma_obj(gem_obj);
8262306a36Sopenharmony_ci	} else {
8362306a36Sopenharmony_ci		dma_obj = kzalloc(sizeof(*dma_obj), GFP_KERNEL);
8462306a36Sopenharmony_ci		if (!dma_obj)
8562306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
8662306a36Sopenharmony_ci		gem_obj = &dma_obj->base;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (!gem_obj->funcs)
9062306a36Sopenharmony_ci		gem_obj->funcs = &drm_gem_dma_default_funcs;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (private) {
9362306a36Sopenharmony_ci		drm_gem_private_object_init(drm, gem_obj, size);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci		/* Always use writecombine for dma-buf mappings */
9662306a36Sopenharmony_ci		dma_obj->map_noncoherent = false;
9762306a36Sopenharmony_ci	} else {
9862306a36Sopenharmony_ci		ret = drm_gem_object_init(drm, gem_obj, size);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	if (ret)
10162306a36Sopenharmony_ci		goto error;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ret = drm_gem_create_mmap_offset(gem_obj);
10462306a36Sopenharmony_ci	if (ret) {
10562306a36Sopenharmony_ci		drm_gem_object_release(gem_obj);
10662306a36Sopenharmony_ci		goto error;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return dma_obj;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cierror:
11262306a36Sopenharmony_ci	kfree(dma_obj);
11362306a36Sopenharmony_ci	return ERR_PTR(ret);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/**
11762306a36Sopenharmony_ci * drm_gem_dma_create - allocate an object with the given size
11862306a36Sopenharmony_ci * @drm: DRM device
11962306a36Sopenharmony_ci * @size: size of the object to allocate
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * This function creates a DMA GEM object and allocates memory as backing store.
12262306a36Sopenharmony_ci * The allocated memory will occupy a contiguous chunk of bus address space.
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * For devices that are directly connected to the memory bus then the allocated
12562306a36Sopenharmony_ci * memory will be physically contiguous. For devices that access through an
12662306a36Sopenharmony_ci * IOMMU, then the allocated memory is not expected to be physically contiguous
12762306a36Sopenharmony_ci * because having contiguous IOVAs is sufficient to meet a devices DMA
12862306a36Sopenharmony_ci * requirements.
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Returns:
13162306a36Sopenharmony_ci * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative
13262306a36Sopenharmony_ci * error code on failure.
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_cistruct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm,
13562306a36Sopenharmony_ci					      size_t size)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
13862306a36Sopenharmony_ci	int ret;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	size = round_up(size, PAGE_SIZE);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	dma_obj = __drm_gem_dma_create(drm, size, false);
14362306a36Sopenharmony_ci	if (IS_ERR(dma_obj))
14462306a36Sopenharmony_ci		return dma_obj;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (dma_obj->map_noncoherent) {
14762306a36Sopenharmony_ci		dma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size,
14862306a36Sopenharmony_ci						       &dma_obj->dma_addr,
14962306a36Sopenharmony_ci						       DMA_TO_DEVICE,
15062306a36Sopenharmony_ci						       GFP_KERNEL | __GFP_NOWARN);
15162306a36Sopenharmony_ci	} else {
15262306a36Sopenharmony_ci		dma_obj->vaddr = dma_alloc_wc(drm->dev, size,
15362306a36Sopenharmony_ci					      &dma_obj->dma_addr,
15462306a36Sopenharmony_ci					      GFP_KERNEL | __GFP_NOWARN);
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	if (!dma_obj->vaddr) {
15762306a36Sopenharmony_ci		drm_dbg(drm, "failed to allocate buffer with size %zu\n",
15862306a36Sopenharmony_ci			 size);
15962306a36Sopenharmony_ci		ret = -ENOMEM;
16062306a36Sopenharmony_ci		goto error;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return dma_obj;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cierror:
16662306a36Sopenharmony_ci	drm_gem_object_put(&dma_obj->base);
16762306a36Sopenharmony_ci	return ERR_PTR(ret);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_create);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * drm_gem_dma_create_with_handle - allocate an object with the given size and
17362306a36Sopenharmony_ci *     return a GEM handle to it
17462306a36Sopenharmony_ci * @file_priv: DRM file-private structure to register the handle for
17562306a36Sopenharmony_ci * @drm: DRM device
17662306a36Sopenharmony_ci * @size: size of the object to allocate
17762306a36Sopenharmony_ci * @handle: return location for the GEM handle
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * This function creates a DMA GEM object, allocating a chunk of memory as
18062306a36Sopenharmony_ci * backing store. The GEM object is then added to the list of object associated
18162306a36Sopenharmony_ci * with the given file and a handle to it is returned.
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * The allocated memory will occupy a contiguous chunk of bus address space.
18462306a36Sopenharmony_ci * See drm_gem_dma_create() for more details.
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * Returns:
18762306a36Sopenharmony_ci * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative
18862306a36Sopenharmony_ci * error code on failure.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_cistatic struct drm_gem_dma_object *
19162306a36Sopenharmony_cidrm_gem_dma_create_with_handle(struct drm_file *file_priv,
19262306a36Sopenharmony_ci			       struct drm_device *drm, size_t size,
19362306a36Sopenharmony_ci			       uint32_t *handle)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
19662306a36Sopenharmony_ci	struct drm_gem_object *gem_obj;
19762306a36Sopenharmony_ci	int ret;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	dma_obj = drm_gem_dma_create(drm, size);
20062306a36Sopenharmony_ci	if (IS_ERR(dma_obj))
20162306a36Sopenharmony_ci		return dma_obj;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	gem_obj = &dma_obj->base;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/*
20662306a36Sopenharmony_ci	 * allocate a id of idr table where the obj is registered
20762306a36Sopenharmony_ci	 * and handle has the id what user can see.
20862306a36Sopenharmony_ci	 */
20962306a36Sopenharmony_ci	ret = drm_gem_handle_create(file_priv, gem_obj, handle);
21062306a36Sopenharmony_ci	/* drop reference from allocate - handle holds it now. */
21162306a36Sopenharmony_ci	drm_gem_object_put(gem_obj);
21262306a36Sopenharmony_ci	if (ret)
21362306a36Sopenharmony_ci		return ERR_PTR(ret);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return dma_obj;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/**
21962306a36Sopenharmony_ci * drm_gem_dma_free - free resources associated with a DMA GEM object
22062306a36Sopenharmony_ci * @dma_obj: DMA GEM object to free
22162306a36Sopenharmony_ci *
22262306a36Sopenharmony_ci * This function frees the backing memory of the DMA GEM object, cleans up the
22362306a36Sopenharmony_ci * GEM object state and frees the memory used to store the object itself.
22462306a36Sopenharmony_ci * If the buffer is imported and the virtual address is set, it is released.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_civoid drm_gem_dma_free(struct drm_gem_dma_object *dma_obj)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct drm_gem_object *gem_obj = &dma_obj->base;
22962306a36Sopenharmony_ci	struct iosys_map map = IOSYS_MAP_INIT_VADDR(dma_obj->vaddr);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (gem_obj->import_attach) {
23262306a36Sopenharmony_ci		if (dma_obj->vaddr)
23362306a36Sopenharmony_ci			dma_buf_vunmap_unlocked(gem_obj->import_attach->dmabuf, &map);
23462306a36Sopenharmony_ci		drm_prime_gem_destroy(gem_obj, dma_obj->sgt);
23562306a36Sopenharmony_ci	} else if (dma_obj->vaddr) {
23662306a36Sopenharmony_ci		if (dma_obj->map_noncoherent)
23762306a36Sopenharmony_ci			dma_free_noncoherent(gem_obj->dev->dev, dma_obj->base.size,
23862306a36Sopenharmony_ci					     dma_obj->vaddr, dma_obj->dma_addr,
23962306a36Sopenharmony_ci					     DMA_TO_DEVICE);
24062306a36Sopenharmony_ci		else
24162306a36Sopenharmony_ci			dma_free_wc(gem_obj->dev->dev, dma_obj->base.size,
24262306a36Sopenharmony_ci				    dma_obj->vaddr, dma_obj->dma_addr);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	drm_gem_object_release(gem_obj);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	kfree(dma_obj);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_free);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/**
25262306a36Sopenharmony_ci * drm_gem_dma_dumb_create_internal - create a dumb buffer object
25362306a36Sopenharmony_ci * @file_priv: DRM file-private structure to create the dumb buffer for
25462306a36Sopenharmony_ci * @drm: DRM device
25562306a36Sopenharmony_ci * @args: IOCTL data
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * This aligns the pitch and size arguments to the minimum required. This is
25862306a36Sopenharmony_ci * an internal helper that can be wrapped by a driver to account for hardware
25962306a36Sopenharmony_ci * with more specific alignment requirements. It should not be used directly
26062306a36Sopenharmony_ci * as their &drm_driver.dumb_create callback.
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Returns:
26362306a36Sopenharmony_ci * 0 on success or a negative error code on failure.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_ciint drm_gem_dma_dumb_create_internal(struct drm_file *file_priv,
26662306a36Sopenharmony_ci				     struct drm_device *drm,
26762306a36Sopenharmony_ci				     struct drm_mode_create_dumb *args)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
27062306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (args->pitch < min_pitch)
27362306a36Sopenharmony_ci		args->pitch = min_pitch;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (args->size < args->pitch * args->height)
27662306a36Sopenharmony_ci		args->size = args->pitch * args->height;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size,
27962306a36Sopenharmony_ci						 &args->handle);
28062306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(dma_obj);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create_internal);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/**
28562306a36Sopenharmony_ci * drm_gem_dma_dumb_create - create a dumb buffer object
28662306a36Sopenharmony_ci * @file_priv: DRM file-private structure to create the dumb buffer for
28762306a36Sopenharmony_ci * @drm: DRM device
28862306a36Sopenharmony_ci * @args: IOCTL data
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci * This function computes the pitch of the dumb buffer and rounds it up to an
29162306a36Sopenharmony_ci * integer number of bytes per pixel. Drivers for hardware that doesn't have
29262306a36Sopenharmony_ci * any additional restrictions on the pitch can directly use this function as
29362306a36Sopenharmony_ci * their &drm_driver.dumb_create callback.
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci * For hardware with additional restrictions, drivers can adjust the fields
29662306a36Sopenharmony_ci * set up by userspace and pass the IOCTL data along to the
29762306a36Sopenharmony_ci * drm_gem_dma_dumb_create_internal() function.
29862306a36Sopenharmony_ci *
29962306a36Sopenharmony_ci * Returns:
30062306a36Sopenharmony_ci * 0 on success or a negative error code on failure.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_ciint drm_gem_dma_dumb_create(struct drm_file *file_priv,
30362306a36Sopenharmony_ci			    struct drm_device *drm,
30462306a36Sopenharmony_ci			    struct drm_mode_create_dumb *args)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
30962306a36Sopenharmony_ci	args->size = args->pitch * args->height;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size,
31262306a36Sopenharmony_ci						 &args->handle);
31362306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(dma_obj);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciconst struct vm_operations_struct drm_gem_dma_vm_ops = {
31862306a36Sopenharmony_ci	.open = drm_gem_vm_open,
31962306a36Sopenharmony_ci	.close = drm_gem_vm_close,
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_vm_ops);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci#ifndef CONFIG_MMU
32462306a36Sopenharmony_ci/**
32562306a36Sopenharmony_ci * drm_gem_dma_get_unmapped_area - propose address for mapping in noMMU cases
32662306a36Sopenharmony_ci * @filp: file object
32762306a36Sopenharmony_ci * @addr: memory address
32862306a36Sopenharmony_ci * @len: buffer size
32962306a36Sopenharmony_ci * @pgoff: page offset
33062306a36Sopenharmony_ci * @flags: memory flags
33162306a36Sopenharmony_ci *
33262306a36Sopenharmony_ci * This function is used in noMMU platforms to propose address mapping
33362306a36Sopenharmony_ci * for a given buffer.
33462306a36Sopenharmony_ci * It's intended to be used as a direct handler for the struct
33562306a36Sopenharmony_ci * &file_operations.get_unmapped_area operation.
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * Returns:
33862306a36Sopenharmony_ci * mapping address on success or a negative error code on failure.
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_ciunsigned long drm_gem_dma_get_unmapped_area(struct file *filp,
34162306a36Sopenharmony_ci					    unsigned long addr,
34262306a36Sopenharmony_ci					    unsigned long len,
34362306a36Sopenharmony_ci					    unsigned long pgoff,
34462306a36Sopenharmony_ci					    unsigned long flags)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
34762306a36Sopenharmony_ci	struct drm_gem_object *obj = NULL;
34862306a36Sopenharmony_ci	struct drm_file *priv = filp->private_data;
34962306a36Sopenharmony_ci	struct drm_device *dev = priv->minor->dev;
35062306a36Sopenharmony_ci	struct drm_vma_offset_node *node;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (drm_dev_is_unplugged(dev))
35362306a36Sopenharmony_ci		return -ENODEV;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
35662306a36Sopenharmony_ci	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
35762306a36Sopenharmony_ci						  pgoff,
35862306a36Sopenharmony_ci						  len >> PAGE_SHIFT);
35962306a36Sopenharmony_ci	if (likely(node)) {
36062306a36Sopenharmony_ci		obj = container_of(node, struct drm_gem_object, vma_node);
36162306a36Sopenharmony_ci		/*
36262306a36Sopenharmony_ci		 * When the object is being freed, after it hits 0-refcnt it
36362306a36Sopenharmony_ci		 * proceeds to tear down the object. In the process it will
36462306a36Sopenharmony_ci		 * attempt to remove the VMA offset and so acquire this
36562306a36Sopenharmony_ci		 * mgr->vm_lock.  Therefore if we find an object with a 0-refcnt
36662306a36Sopenharmony_ci		 * that matches our range, we know it is in the process of being
36762306a36Sopenharmony_ci		 * destroyed and will be freed as soon as we release the lock -
36862306a36Sopenharmony_ci		 * so we have to check for the 0-refcnted object and treat it as
36962306a36Sopenharmony_ci		 * invalid.
37062306a36Sopenharmony_ci		 */
37162306a36Sopenharmony_ci		if (!kref_get_unless_zero(&obj->refcount))
37262306a36Sopenharmony_ci			obj = NULL;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (!obj)
37862306a36Sopenharmony_ci		return -EINVAL;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (!drm_vma_node_is_allowed(node, priv)) {
38162306a36Sopenharmony_ci		drm_gem_object_put(obj);
38262306a36Sopenharmony_ci		return -EACCES;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dma_obj = to_drm_gem_dma_obj(obj);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	drm_gem_object_put(obj);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return dma_obj->vaddr ? (unsigned long)dma_obj->vaddr : -EINVAL;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_get_unmapped_area);
39262306a36Sopenharmony_ci#endif
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci/**
39562306a36Sopenharmony_ci * drm_gem_dma_print_info() - Print &drm_gem_dma_object info for debugfs
39662306a36Sopenharmony_ci * @dma_obj: DMA GEM object
39762306a36Sopenharmony_ci * @p: DRM printer
39862306a36Sopenharmony_ci * @indent: Tab indentation level
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * This function prints dma_addr and vaddr for use in e.g. debugfs output.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_civoid drm_gem_dma_print_info(const struct drm_gem_dma_object *dma_obj,
40362306a36Sopenharmony_ci			    struct drm_printer *p, unsigned int indent)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	drm_printf_indent(p, indent, "dma_addr=%pad\n", &dma_obj->dma_addr);
40662306a36Sopenharmony_ci	drm_printf_indent(p, indent, "vaddr=%p\n", dma_obj->vaddr);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_dma_print_info);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/**
41162306a36Sopenharmony_ci * drm_gem_dma_get_sg_table - provide a scatter/gather table of pinned
41262306a36Sopenharmony_ci *     pages for a DMA GEM object
41362306a36Sopenharmony_ci * @dma_obj: DMA GEM object
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * This function exports a scatter/gather table by calling the standard
41662306a36Sopenharmony_ci * DMA mapping API.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * Returns:
41962306a36Sopenharmony_ci * A pointer to the scatter/gather table of pinned pages or NULL on failure.
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistruct sg_table *drm_gem_dma_get_sg_table(struct drm_gem_dma_object *dma_obj)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct drm_gem_object *obj = &dma_obj->base;
42462306a36Sopenharmony_ci	struct sg_table *sgt;
42562306a36Sopenharmony_ci	int ret;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
42862306a36Sopenharmony_ci	if (!sgt)
42962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	ret = dma_get_sgtable(obj->dev->dev, sgt, dma_obj->vaddr,
43262306a36Sopenharmony_ci			      dma_obj->dma_addr, obj->size);
43362306a36Sopenharmony_ci	if (ret < 0)
43462306a36Sopenharmony_ci		goto out;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return sgt;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciout:
43962306a36Sopenharmony_ci	kfree(sgt);
44062306a36Sopenharmony_ci	return ERR_PTR(ret);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_get_sg_table);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/**
44562306a36Sopenharmony_ci * drm_gem_dma_prime_import_sg_table - produce a DMA GEM object from another
44662306a36Sopenharmony_ci *     driver's scatter/gather table of pinned pages
44762306a36Sopenharmony_ci * @dev: device to import into
44862306a36Sopenharmony_ci * @attach: DMA-BUF attachment
44962306a36Sopenharmony_ci * @sgt: scatter/gather table of pinned pages
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci * This function imports a scatter/gather table exported via DMA-BUF by
45262306a36Sopenharmony_ci * another driver. Imported buffers must be physically contiguous in memory
45362306a36Sopenharmony_ci * (i.e. the scatter/gather table must contain a single entry). Drivers that
45462306a36Sopenharmony_ci * use the DMA helpers should set this as their
45562306a36Sopenharmony_ci * &drm_driver.gem_prime_import_sg_table callback.
45662306a36Sopenharmony_ci *
45762306a36Sopenharmony_ci * Returns:
45862306a36Sopenharmony_ci * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
45962306a36Sopenharmony_ci * error code on failure.
46062306a36Sopenharmony_ci */
46162306a36Sopenharmony_cistruct drm_gem_object *
46262306a36Sopenharmony_cidrm_gem_dma_prime_import_sg_table(struct drm_device *dev,
46362306a36Sopenharmony_ci				  struct dma_buf_attachment *attach,
46462306a36Sopenharmony_ci				  struct sg_table *sgt)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* check if the entries in the sg_table are contiguous */
46962306a36Sopenharmony_ci	if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size)
47062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Create a DMA GEM buffer. */
47362306a36Sopenharmony_ci	dma_obj = __drm_gem_dma_create(dev, attach->dmabuf->size, true);
47462306a36Sopenharmony_ci	if (IS_ERR(dma_obj))
47562306a36Sopenharmony_ci		return ERR_CAST(dma_obj);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	dma_obj->dma_addr = sg_dma_address(sgt->sgl);
47862306a36Sopenharmony_ci	dma_obj->sgt = sgt;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	drm_dbg_prime(dev, "dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr,
48162306a36Sopenharmony_ci		      attach->dmabuf->size);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return &dma_obj->base;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_prime_import_sg_table);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/**
48862306a36Sopenharmony_ci * drm_gem_dma_vmap - map a DMA GEM object into the kernel's virtual
48962306a36Sopenharmony_ci *     address space
49062306a36Sopenharmony_ci * @dma_obj: DMA GEM object
49162306a36Sopenharmony_ci * @map: Returns the kernel virtual address of the DMA GEM object's backing
49262306a36Sopenharmony_ci *       store.
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * This function maps a buffer into the kernel's virtual address space.
49562306a36Sopenharmony_ci * Since the DMA buffers are already mapped into the kernel virtual address
49662306a36Sopenharmony_ci * space this simply returns the cached virtual address.
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Returns:
49962306a36Sopenharmony_ci * 0 on success, or a negative error code otherwise.
50062306a36Sopenharmony_ci */
50162306a36Sopenharmony_ciint drm_gem_dma_vmap(struct drm_gem_dma_object *dma_obj,
50262306a36Sopenharmony_ci		     struct iosys_map *map)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	iosys_map_set_vaddr(map, dma_obj->vaddr);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_vmap);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/**
51162306a36Sopenharmony_ci * drm_gem_dma_mmap - memory-map an exported DMA GEM object
51262306a36Sopenharmony_ci * @dma_obj: DMA GEM object
51362306a36Sopenharmony_ci * @vma: VMA for the area to be mapped
51462306a36Sopenharmony_ci *
51562306a36Sopenharmony_ci * This function maps a buffer into a userspace process's address space.
51662306a36Sopenharmony_ci * In addition to the usual GEM VMA setup it immediately faults in the entire
51762306a36Sopenharmony_ci * object instead of using on-demand faulting.
51862306a36Sopenharmony_ci *
51962306a36Sopenharmony_ci * Returns:
52062306a36Sopenharmony_ci * 0 on success or a negative error code on failure.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_ciint drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *vma)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct drm_gem_object *obj = &dma_obj->base;
52562306a36Sopenharmony_ci	int ret;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/*
52862306a36Sopenharmony_ci	 * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
52962306a36Sopenharmony_ci	 * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
53062306a36Sopenharmony_ci	 * the whole buffer.
53162306a36Sopenharmony_ci	 */
53262306a36Sopenharmony_ci	vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
53362306a36Sopenharmony_ci	vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (dma_obj->map_noncoherent) {
53662306a36Sopenharmony_ci		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		ret = dma_mmap_pages(dma_obj->base.dev->dev,
53962306a36Sopenharmony_ci				     vma, vma->vm_end - vma->vm_start,
54062306a36Sopenharmony_ci				     virt_to_page(dma_obj->vaddr));
54162306a36Sopenharmony_ci	} else {
54262306a36Sopenharmony_ci		ret = dma_mmap_wc(dma_obj->base.dev->dev, vma, dma_obj->vaddr,
54362306a36Sopenharmony_ci				  dma_obj->dma_addr,
54462306a36Sopenharmony_ci				  vma->vm_end - vma->vm_start);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	if (ret)
54762306a36Sopenharmony_ci		drm_gem_vm_close(vma);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return ret;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_dma_mmap);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/**
55462306a36Sopenharmony_ci * drm_gem_dma_prime_import_sg_table_vmap - PRIME import another driver's
55562306a36Sopenharmony_ci *	scatter/gather table and get the virtual address of the buffer
55662306a36Sopenharmony_ci * @dev: DRM device
55762306a36Sopenharmony_ci * @attach: DMA-BUF attachment
55862306a36Sopenharmony_ci * @sgt: Scatter/gather table of pinned pages
55962306a36Sopenharmony_ci *
56062306a36Sopenharmony_ci * This function imports a scatter/gather table using
56162306a36Sopenharmony_ci * drm_gem_dma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel
56262306a36Sopenharmony_ci * virtual address. This ensures that a DMA GEM object always has its virtual
56362306a36Sopenharmony_ci * address set. This address is released when the object is freed.
56462306a36Sopenharmony_ci *
56562306a36Sopenharmony_ci * This function can be used as the &drm_driver.gem_prime_import_sg_table
56662306a36Sopenharmony_ci * callback. The &DRM_GEM_DMA_DRIVER_OPS_VMAP macro provides a shortcut to set
56762306a36Sopenharmony_ci * the necessary DRM driver operations.
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * Returns:
57062306a36Sopenharmony_ci * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
57162306a36Sopenharmony_ci * error code on failure.
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cistruct drm_gem_object *
57462306a36Sopenharmony_cidrm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev,
57562306a36Sopenharmony_ci				       struct dma_buf_attachment *attach,
57662306a36Sopenharmony_ci				       struct sg_table *sgt)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct drm_gem_dma_object *dma_obj;
57962306a36Sopenharmony_ci	struct drm_gem_object *obj;
58062306a36Sopenharmony_ci	struct iosys_map map;
58162306a36Sopenharmony_ci	int ret;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	ret = dma_buf_vmap_unlocked(attach->dmabuf, &map);
58462306a36Sopenharmony_ci	if (ret) {
58562306a36Sopenharmony_ci		DRM_ERROR("Failed to vmap PRIME buffer\n");
58662306a36Sopenharmony_ci		return ERR_PTR(ret);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt);
59062306a36Sopenharmony_ci	if (IS_ERR(obj)) {
59162306a36Sopenharmony_ci		dma_buf_vunmap_unlocked(attach->dmabuf, &map);
59262306a36Sopenharmony_ci		return obj;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	dma_obj = to_drm_gem_dma_obj(obj);
59662306a36Sopenharmony_ci	dma_obj->vaddr = map.vaddr;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	return obj;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_gem_dma_prime_import_sg_table_vmap);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ciMODULE_DESCRIPTION("DRM DMA memory-management helpers");
60362306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF);
60462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
605