drm/vmwgfx: Fix prime import/export
vmwgfx never supported prime import of external buffers. Furthermore the
driver exposes two different objects to userspace: vmw_surface's and
gem buffers but prime import/export only worked with vmw_surfaces.
Because gem buffers are used through the dumb_buffer interface this meant
that the driver created buffers couldn't have been prime exported or
imported.
Fix prime import/export. Makes IGT's kms_prime pass.
Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Fixes: 8afa13a058
("drm/vmwgfx: Implement DRIVER_GEM")
Cc: <stable@vger.kernel.org> # v6.6+
Reviewed-by: Martin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240412025511.78553-4-zack.rusin@broadcom.com
This commit is contained in:
parent
b6976f323a
commit
b32233acce
8 changed files with 117 additions and 22 deletions
|
@ -456,8 +456,10 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst,
|
||||||
.no_wait_gpu = false
|
.no_wait_gpu = false
|
||||||
};
|
};
|
||||||
u32 j, initial_line = dst_offset / dst_stride;
|
u32 j, initial_line = dst_offset / dst_stride;
|
||||||
struct vmw_bo_blit_line_data d;
|
struct vmw_bo_blit_line_data d = {0};
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct page **dst_pages = NULL;
|
||||||
|
struct page **src_pages = NULL;
|
||||||
|
|
||||||
/* Buffer objects need to be either pinned or reserved: */
|
/* Buffer objects need to be either pinned or reserved: */
|
||||||
if (!(dst->pin_count))
|
if (!(dst->pin_count))
|
||||||
|
@ -477,12 +479,35 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!src->ttm->pages && src->ttm->sg) {
|
||||||
|
src_pages = kvmalloc_array(src->ttm->num_pages,
|
||||||
|
sizeof(struct page *), GFP_KERNEL);
|
||||||
|
if (!src_pages)
|
||||||
|
return -ENOMEM;
|
||||||
|
ret = drm_prime_sg_to_page_array(src->ttm->sg, src_pages,
|
||||||
|
src->ttm->num_pages);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!dst->ttm->pages && dst->ttm->sg) {
|
||||||
|
dst_pages = kvmalloc_array(dst->ttm->num_pages,
|
||||||
|
sizeof(struct page *), GFP_KERNEL);
|
||||||
|
if (!dst_pages) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = drm_prime_sg_to_page_array(dst->ttm->sg, dst_pages,
|
||||||
|
dst->ttm->num_pages);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
d.mapped_dst = 0;
|
d.mapped_dst = 0;
|
||||||
d.mapped_src = 0;
|
d.mapped_src = 0;
|
||||||
d.dst_addr = NULL;
|
d.dst_addr = NULL;
|
||||||
d.src_addr = NULL;
|
d.src_addr = NULL;
|
||||||
d.dst_pages = dst->ttm->pages;
|
d.dst_pages = dst->ttm->pages ? dst->ttm->pages : dst_pages;
|
||||||
d.src_pages = src->ttm->pages;
|
d.src_pages = src->ttm->pages ? src->ttm->pages : src_pages;
|
||||||
d.dst_num_pages = PFN_UP(dst->resource->size);
|
d.dst_num_pages = PFN_UP(dst->resource->size);
|
||||||
d.src_num_pages = PFN_UP(src->resource->size);
|
d.src_num_pages = PFN_UP(src->resource->size);
|
||||||
d.dst_prot = ttm_io_prot(dst, dst->resource, PAGE_KERNEL);
|
d.dst_prot = ttm_io_prot(dst, dst->resource, PAGE_KERNEL);
|
||||||
|
@ -504,6 +529,10 @@ out:
|
||||||
kunmap_atomic(d.src_addr);
|
kunmap_atomic(d.src_addr);
|
||||||
if (d.dst_addr)
|
if (d.dst_addr)
|
||||||
kunmap_atomic(d.dst_addr);
|
kunmap_atomic(d.dst_addr);
|
||||||
|
if (src_pages)
|
||||||
|
kvfree(src_pages);
|
||||||
|
if (dst_pages)
|
||||||
|
kvfree(dst_pages);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,8 @@ static int vmw_bo_init(struct vmw_private *dev_priv,
|
||||||
{
|
{
|
||||||
struct ttm_operation_ctx ctx = {
|
struct ttm_operation_ctx ctx = {
|
||||||
.interruptible = params->bo_type != ttm_bo_type_kernel,
|
.interruptible = params->bo_type != ttm_bo_type_kernel,
|
||||||
.no_wait_gpu = false
|
.no_wait_gpu = false,
|
||||||
|
.resv = params->resv,
|
||||||
};
|
};
|
||||||
struct ttm_device *bdev = &dev_priv->bdev;
|
struct ttm_device *bdev = &dev_priv->bdev;
|
||||||
struct drm_device *vdev = &dev_priv->drm;
|
struct drm_device *vdev = &dev_priv->drm;
|
||||||
|
@ -394,8 +395,8 @@ static int vmw_bo_init(struct vmw_private *dev_priv,
|
||||||
|
|
||||||
vmw_bo_placement_set(vmw_bo, params->domain, params->busy_domain);
|
vmw_bo_placement_set(vmw_bo, params->domain, params->busy_domain);
|
||||||
ret = ttm_bo_init_reserved(bdev, &vmw_bo->tbo, params->bo_type,
|
ret = ttm_bo_init_reserved(bdev, &vmw_bo->tbo, params->bo_type,
|
||||||
&vmw_bo->placement, 0, &ctx, NULL,
|
&vmw_bo->placement, 0, &ctx,
|
||||||
NULL, destroy);
|
params->sg, params->resv, destroy);
|
||||||
if (unlikely(ret))
|
if (unlikely(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ struct vmw_bo_params {
|
||||||
enum ttm_bo_type bo_type;
|
enum ttm_bo_type bo_type;
|
||||||
size_t size;
|
size_t size;
|
||||||
bool pin;
|
bool pin;
|
||||||
|
struct dma_resv *resv;
|
||||||
|
struct sg_table *sg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1628,6 +1628,7 @@ static const struct drm_driver driver = {
|
||||||
|
|
||||||
.prime_fd_to_handle = vmw_prime_fd_to_handle,
|
.prime_fd_to_handle = vmw_prime_fd_to_handle,
|
||||||
.prime_handle_to_fd = vmw_prime_handle_to_fd,
|
.prime_handle_to_fd = vmw_prime_handle_to_fd,
|
||||||
|
.gem_prime_import_sg_table = vmw_prime_import_sg_table,
|
||||||
|
|
||||||
.fops = &vmwgfx_driver_fops,
|
.fops = &vmwgfx_driver_fops,
|
||||||
.name = VMWGFX_DRIVER_NAME,
|
.name = VMWGFX_DRIVER_NAME,
|
||||||
|
|
|
@ -1130,6 +1130,9 @@ extern int vmw_prime_handle_to_fd(struct drm_device *dev,
|
||||||
struct drm_file *file_priv,
|
struct drm_file *file_priv,
|
||||||
uint32_t handle, uint32_t flags,
|
uint32_t handle, uint32_t flags,
|
||||||
int *prime_fd);
|
int *prime_fd);
|
||||||
|
struct drm_gem_object *vmw_prime_import_sg_table(struct drm_device *dev,
|
||||||
|
struct dma_buf_attachment *attach,
|
||||||
|
struct sg_table *table);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MemoryOBject management - vmwgfx_mob.c
|
* MemoryOBject management - vmwgfx_mob.c
|
||||||
|
|
|
@ -149,6 +149,38 @@ out_no_bo:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct drm_gem_object *vmw_prime_import_sg_table(struct drm_device *dev,
|
||||||
|
struct dma_buf_attachment *attach,
|
||||||
|
struct sg_table *table)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
||||||
|
struct drm_gem_object *gem = NULL;
|
||||||
|
struct vmw_bo *vbo;
|
||||||
|
struct vmw_bo_params params = {
|
||||||
|
.domain = (dev_priv->has_mob) ? VMW_BO_DOMAIN_SYS : VMW_BO_DOMAIN_VRAM,
|
||||||
|
.busy_domain = VMW_BO_DOMAIN_SYS,
|
||||||
|
.bo_type = ttm_bo_type_sg,
|
||||||
|
.size = attach->dmabuf->size,
|
||||||
|
.pin = false,
|
||||||
|
.resv = attach->dmabuf->resv,
|
||||||
|
.sg = table,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
dma_resv_lock(params.resv, NULL);
|
||||||
|
|
||||||
|
ret = vmw_bo_create(dev_priv, ¶ms, &vbo);
|
||||||
|
if (ret != 0)
|
||||||
|
goto out_no_bo;
|
||||||
|
|
||||||
|
vbo->tbo.base.funcs = &vmw_gem_object_funcs;
|
||||||
|
|
||||||
|
gem = &vbo->tbo.base;
|
||||||
|
out_no_bo:
|
||||||
|
dma_resv_unlock(params.resv);
|
||||||
|
return gem;
|
||||||
|
}
|
||||||
|
|
||||||
int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data,
|
int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *filp)
|
struct drm_file *filp)
|
||||||
|
|
|
@ -75,8 +75,12 @@ int vmw_prime_fd_to_handle(struct drm_device *dev,
|
||||||
int fd, u32 *handle)
|
int fd, u32 *handle)
|
||||||
{
|
{
|
||||||
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
||||||
|
int ret = ttm_prime_fd_to_handle(tfile, fd, handle);
|
||||||
|
|
||||||
return ttm_prime_fd_to_handle(tfile, fd, handle);
|
if (ret)
|
||||||
|
ret = drm_gem_prime_fd_to_handle(dev, file_priv, fd, handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vmw_prime_handle_to_fd(struct drm_device *dev,
|
int vmw_prime_handle_to_fd(struct drm_device *dev,
|
||||||
|
@ -85,5 +89,12 @@ int vmw_prime_handle_to_fd(struct drm_device *dev,
|
||||||
int *prime_fd)
|
int *prime_fd)
|
||||||
{
|
{
|
||||||
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
||||||
return ttm_prime_handle_to_fd(tfile, handle, flags, prime_fd);
|
int ret;
|
||||||
|
|
||||||
|
if (handle > VMWGFX_NUM_MOB)
|
||||||
|
ret = ttm_prime_handle_to_fd(tfile, handle, flags, prime_fd);
|
||||||
|
else
|
||||||
|
ret = drm_gem_prime_handle_to_fd(dev, file_priv, handle, flags, prime_fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,13 +188,18 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
|
||||||
switch (dev_priv->map_mode) {
|
switch (dev_priv->map_mode) {
|
||||||
case vmw_dma_map_bind:
|
case vmw_dma_map_bind:
|
||||||
case vmw_dma_map_populate:
|
case vmw_dma_map_populate:
|
||||||
|
if (vmw_tt->dma_ttm.page_flags & TTM_TT_FLAG_EXTERNAL) {
|
||||||
|
vsgt->sgt = vmw_tt->dma_ttm.sg;
|
||||||
|
} else {
|
||||||
vsgt->sgt = &vmw_tt->sgt;
|
vsgt->sgt = &vmw_tt->sgt;
|
||||||
ret = sg_alloc_table_from_pages_segment(
|
ret = sg_alloc_table_from_pages_segment(&vmw_tt->sgt,
|
||||||
&vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0,
|
vsgt->pages, vsgt->num_pages, 0,
|
||||||
(unsigned long)vsgt->num_pages << PAGE_SHIFT,
|
(unsigned long)vsgt->num_pages << PAGE_SHIFT,
|
||||||
dma_get_max_seg_size(dev_priv->drm.dev), GFP_KERNEL);
|
dma_get_max_seg_size(dev_priv->drm.dev),
|
||||||
|
GFP_KERNEL);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_sg_alloc_fail;
|
goto out_sg_alloc_fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = vmw_ttm_map_for_dma(vmw_tt);
|
ret = vmw_ttm_map_for_dma(vmw_tt);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
|
@ -209,8 +214,9 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_map_fail:
|
out_map_fail:
|
||||||
sg_free_table(vmw_tt->vsgt.sgt);
|
drm_warn(&dev_priv->drm, "VSG table map failed!");
|
||||||
vmw_tt->vsgt.sgt = NULL;
|
sg_free_table(vsgt->sgt);
|
||||||
|
vsgt->sgt = NULL;
|
||||||
out_sg_alloc_fail:
|
out_sg_alloc_fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -356,15 +362,17 @@ static void vmw_ttm_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
|
||||||
static int vmw_ttm_populate(struct ttm_device *bdev,
|
static int vmw_ttm_populate(struct ttm_device *bdev,
|
||||||
struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
|
struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
bool external = (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) != 0;
|
||||||
|
|
||||||
/* TODO: maybe completely drop this ? */
|
|
||||||
if (ttm_tt_is_populated(ttm))
|
if (ttm_tt_is_populated(ttm))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = ttm_pool_alloc(&bdev->pool, ttm, ctx);
|
if (external && ttm->sg)
|
||||||
|
return drm_prime_sg_to_dma_addr_array(ttm->sg,
|
||||||
|
ttm->dma_address,
|
||||||
|
ttm->num_pages);
|
||||||
|
|
||||||
return ret;
|
return ttm_pool_alloc(&bdev->pool, ttm, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmw_ttm_unpopulate(struct ttm_device *bdev,
|
static void vmw_ttm_unpopulate(struct ttm_device *bdev,
|
||||||
|
@ -372,6 +380,10 @@ static void vmw_ttm_unpopulate(struct ttm_device *bdev,
|
||||||
{
|
{
|
||||||
struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
|
struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
|
||||||
dma_ttm);
|
dma_ttm);
|
||||||
|
bool external = (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) != 0;
|
||||||
|
|
||||||
|
if (external)
|
||||||
|
return;
|
||||||
|
|
||||||
vmw_ttm_unbind(bdev, ttm);
|
vmw_ttm_unbind(bdev, ttm);
|
||||||
|
|
||||||
|
@ -390,6 +402,7 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
|
||||||
{
|
{
|
||||||
struct vmw_ttm_tt *vmw_be;
|
struct vmw_ttm_tt *vmw_be;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool external = bo->type == ttm_bo_type_sg;
|
||||||
|
|
||||||
vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
|
vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
|
||||||
if (!vmw_be)
|
if (!vmw_be)
|
||||||
|
@ -398,7 +411,10 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
|
||||||
vmw_be->dev_priv = vmw_priv_from_ttm(bo->bdev);
|
vmw_be->dev_priv = vmw_priv_from_ttm(bo->bdev);
|
||||||
vmw_be->mob = NULL;
|
vmw_be->mob = NULL;
|
||||||
|
|
||||||
if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
|
if (external)
|
||||||
|
page_flags |= TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE;
|
||||||
|
|
||||||
|
if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent || external)
|
||||||
ret = ttm_sg_tt_init(&vmw_be->dma_ttm, bo, page_flags,
|
ret = ttm_sg_tt_init(&vmw_be->dma_ttm, bo, page_flags,
|
||||||
ttm_cached);
|
ttm_cached);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Add table
Reference in a new issue