Commit 6e6db272 authored by Christian König's avatar Christian König
Browse files

drm/amdgpu: add independent DMA-buf export v8



Add an DMA-buf export implementation independent of the DRM helpers.

This not only avoids the caching of DMA-buf mappings, but also
allows us to use the new dynamic locking approach.

This is also a prerequisite of unpinned DMA-buf handling.

v2: fix unintended recursion, remove debugging leftovers
v3: split out from unpinned DMA-buf work
v4: rebase on top of new no_sgt_cache flag
v5: fix some warnings by including amdgpu_dma_buf.h
v6: fix locking for non amdgpu exports
v7: rebased on new DMA-buf locking patch
v8: drop extra include

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/337949/
parent 955a72ce
Loading
Loading
Loading
Loading
+96 −76
Original line number Diff line number Diff line
@@ -34,26 +34,11 @@
#include "amdgpu.h"
#include "amdgpu_display.h"
#include "amdgpu_gem.h"
#include "amdgpu_dma_buf.h"
#include <drm/amdgpu_drm.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence-array.h>

/**
 * amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table
 * implementation
 * @obj: GEM buffer object (BO)
 *
 * Returns:
 * A scatter/gather table for the pinned pages of the BO's memory.
 */
struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
	int npages = bo->tbo.num_pages;

	return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
}

/**
 * amdgpu_gem_prime_vmap - &dma_buf_ops.vmap implementation
 * @obj: GEM BO
@@ -179,35 +164,28 @@ err_fences_put:
}

/**
 * amdgpu_dma_buf_map_attach - &dma_buf_ops.attach implementation
 * @dma_buf: Shared DMA buffer
 * @attach: DMA-buf attachment
 * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation
 *
 * Makes sure that the shared DMA buffer can be accessed by the target device.
 * For now, simply pins it to the GTT domain, where it should be accessible by
 * all DMA devices.
 * @dmabuf: DMA-buf where we attach to
 * @attach: attachment to add
 *
 * Returns:
 * 0 on success or a negative error code on failure.
 * Add the attachment as user to the exported DMA-buf.
 */
static int amdgpu_dma_buf_map_attach(struct dma_buf *dma_buf,
static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
				 struct dma_buf_attachment *attach)
{
	struct drm_gem_object *obj = dma_buf->priv;
	struct drm_gem_object *obj = dmabuf->priv;
	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
	long r;
	int r;

	r = drm_gem_map_attach(dma_buf, attach);
	if (r)
		return r;
	if (attach->dev->driver == adev->dev->driver)
		return 0;

	r = amdgpu_bo_reserve(bo, false);
	if (unlikely(r != 0))
		goto error_detach;

		return r;

	if (attach->dev->driver != adev->dev->driver) {
	/*
	 * We only create shared fences for internal use, but importers
	 * of the dmabuf rely on exclusive fences for implicitly
@@ -218,53 +196,94 @@ static int amdgpu_dma_buf_map_attach(struct dma_buf *dma_buf,
	 */
	r = __dma_resv_make_exclusive(bo->tbo.base.resv);
	if (r)
			goto error_unreserve;
		return r;

	bo->prime_shared_count++;
	amdgpu_bo_unreserve(bo);
	return 0;
}

/**
 * amdgpu_dma_buf_detach - &dma_buf_ops.detach implementation
 *
 * @dmabuf: DMA-buf where we remove the attachment from
 * @attach: the attachment to remove
 *
 * Called when an attachment is removed from the DMA-buf.
 */
static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf,
				  struct dma_buf_attachment *attach)
{
	struct drm_gem_object *obj = dmabuf->priv;
	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);

	if (attach->dev->driver != adev->dev->driver && bo->prime_shared_count)
		bo->prime_shared_count--;
}

	/* pin buffer into GTT */
/**
 * amdgpu_dma_buf_map - &dma_buf_ops.map_dma_buf implementation
 * @attach: DMA-buf attachment
 * @dir: DMA direction
 *
 * Makes sure that the shared DMA buffer can be accessed by the target device.
 * For now, simply pins it to the GTT domain, where it should be accessible by
 * all DMA devices.
 *
 * Returns:
 * sg_table filled with the DMA addresses to use or ERR_PRT with negative error
 * code.
 */
static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
					   enum dma_data_direction dir)
{
	struct dma_buf *dma_buf = attach->dmabuf;
	struct drm_gem_object *obj = dma_buf->priv;
	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
	struct sg_table *sgt;
	long r;

	r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
	if (r)
		goto error_unreserve;
		return ERR_PTR(r);

	if (attach->dev->driver != adev->dev->driver)
		bo->prime_shared_count++;
	sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages, bo->tbo.num_pages);
	if (IS_ERR(sgt))
		return sgt;

error_unreserve:
	amdgpu_bo_unreserve(bo);
	if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
			      DMA_ATTR_SKIP_CPU_SYNC))
		goto error_free;

error_detach:
	if (r)
		drm_gem_map_detach(dma_buf, attach);
	return r;
	return sgt;

error_free:
	sg_free_table(sgt);
	kfree(sgt);
	return ERR_PTR(-ENOMEM);
}

/**
 * amdgpu_dma_buf_map_detach - &dma_buf_ops.detach implementation
 * @dma_buf: Shared DMA buffer
 * amdgpu_dma_buf_unmap - &dma_buf_ops.unmap_dma_buf implementation
 * @attach: DMA-buf attachment
 * @sgt: sg_table to unmap
 * @dir: DMA direction
 *
 * This is called when a shared DMA buffer no longer needs to be accessible by
 * another device. For now, simply unpins the buffer from GTT.
 */
static void amdgpu_dma_buf_map_detach(struct dma_buf *dma_buf,
				      struct dma_buf_attachment *attach)
static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
				 struct sg_table *sgt,
				 enum dma_data_direction dir)
{
	struct drm_gem_object *obj = dma_buf->priv;
	struct drm_gem_object *obj = attach->dmabuf->priv;
	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
	int ret = 0;

	ret = amdgpu_bo_reserve(bo, true);
	if (unlikely(ret != 0))
		goto error;

	dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
	sg_free_table(sgt);
	kfree(sgt);
	amdgpu_bo_unpin(bo);
	if (attach->dev->driver != adev->dev->driver && bo->prime_shared_count)
		bo->prime_shared_count--;
	amdgpu_bo_unreserve(bo);

error:
	drm_gem_map_detach(dma_buf, attach);
}

/**
@@ -308,10 +327,11 @@ static int amdgpu_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
}

const struct dma_buf_ops amdgpu_dmabuf_ops = {
	.attach = amdgpu_dma_buf_map_attach,
	.detach = amdgpu_dma_buf_map_detach,
	.map_dma_buf = drm_gem_map_dma_buf,
	.unmap_dma_buf = drm_gem_unmap_dma_buf,
	.dynamic_mapping = true,
	.attach = amdgpu_dma_buf_attach,
	.detach = amdgpu_dma_buf_detach,
	.map_dma_buf = amdgpu_dma_buf_map,
	.unmap_dma_buf = amdgpu_dma_buf_unmap,
	.release = drm_gem_dmabuf_release,
	.begin_cpu_access = amdgpu_dma_buf_begin_cpu_access,
	.mmap = drm_gem_dmabuf_mmap,
+0 −1
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@

#include <drm/drm_gem.h>

struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *
amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
				 struct dma_buf_attachment *attach,
+0 −1
Original line number Diff line number Diff line
@@ -1445,7 +1445,6 @@ static struct drm_driver kms_driver = {
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_export = amdgpu_gem_prime_export,
	.gem_prime_import = amdgpu_gem_prime_import,
	.gem_prime_get_sg_table = amdgpu_gem_prime_get_sg_table,
	.gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table,
	.gem_prime_vmap = amdgpu_gem_prime_vmap,
	.gem_prime_vunmap = amdgpu_gem_prime_vunmap,