Skip to content

Commit

Permalink
drm/vmwgfx: Fix handling of dumb buffers
Browse files Browse the repository at this point in the history
Dumb buffers can be used in kms but also through prime with gallium's
resource_from_handle. In the second case the dumb buffers can be
rendered by the GPU where with the regular DRM kms interfaces they
are mapped and written to by the CPU. Because the same buffer can
be written to by the GPU and CPU vmwgfx needs to use vmw_surface (object
which properly tracks dirty state of the guest and gpu memory)
instead of vmw_bo (which is just guest side memory).

Furthermore the dumb buffer handles are expected to be gem objects by
a lot of userspace.

Make vmwgfx accept gem handles in prime and kms but internally switch
to vmw_surface's to properly track the dirty state of the objects between
the GPU and CPU.

Fixes new kwin and kde on wayland.

Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Fixes: b32233a ("drm/vmwgfx: Fix prime import/export")
Cc: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
Cc: dri-devel@lists.freedesktop.org
Cc: <stable@vger.kernel.org> # v6.9+
Reviewed-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Reviewed-by: Martin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240722184313.181318-4-zack.rusin@broadcom.com
  • Loading branch information
Zack Rusin committed Jul 25, 2024
1 parent 09f34a0 commit d6667f0
Show file tree
Hide file tree
Showing 12 changed files with 740 additions and 502 deletions.
10 changes: 8 additions & 2 deletions drivers/gpu/drm/vmwgfx/vmw_surface_cache.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**********************************************************
* Copyright 2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
Expand Down Expand Up @@ -31,6 +33,10 @@

#include <drm/vmwgfx_drm.h>

#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32)
#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
((svga3d_flags) & ((uint64_t)U32_MAX))

static inline u32 clamped_umul32(u32 a, u32 b)
{
uint64_t tmp = (uint64_t) a*b;
Expand Down
127 changes: 76 additions & 51 deletions drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright © 2011-2023 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
* Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
Expand All @@ -28,15 +28,39 @@

#include "vmwgfx_bo.h"
#include "vmwgfx_drv.h"

#include "vmwgfx_resource_priv.h"

#include <drm/ttm/ttm_placement.h>

static void vmw_bo_release(struct vmw_bo *vbo)
{
struct vmw_resource *res;

WARN_ON(vbo->tbo.base.funcs &&
kref_read(&vbo->tbo.base.refcount) != 0);
vmw_bo_unmap(vbo);

xa_destroy(&vbo->detached_resources);
WARN_ON(vbo->is_dumb && !vbo->dumb_surface);
if (vbo->is_dumb && vbo->dumb_surface) {
res = &vbo->dumb_surface->res;
WARN_ON(vbo != res->guest_memory_bo);
WARN_ON(!res->guest_memory_bo);
if (res->guest_memory_bo) {
/* Reserve and switch the backing mob. */
mutex_lock(&res->dev_priv->cmdbuf_mutex);
(void)vmw_resource_reserve(res, false, true);
vmw_resource_mob_detach(res);
if (res->coherent)
vmw_bo_dirty_release(res->guest_memory_bo);
res->guest_memory_bo = NULL;
res->guest_memory_offset = 0;
vmw_resource_unreserve(res, false, false, false, NULL,
0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
}
vmw_surface_unreference(&vbo->dumb_surface);
}
drm_gem_object_release(&vbo->tbo.base);
}

Expand Down Expand Up @@ -325,6 +349,11 @@ void vmw_bo_pin_reserved(struct vmw_bo *vbo, bool pin)
*
*/
void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
{
return vmw_bo_map_and_cache_size(vbo, vbo->tbo.base.size);
}

void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size)
{
struct ttm_buffer_object *bo = &vbo->tbo;
bool not_used;
Expand All @@ -335,9 +364,10 @@ void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
if (virtual)
return virtual;

ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map);
ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vbo->map);
if (ret)
DRM_ERROR("Buffer object map failed: %d.\n", ret);
DRM_ERROR("Buffer object map failed: %d (size: bo = %zu, map = %zu).\n",
ret, bo->base.size, size);

return ttm_kmap_obj_virtual(&vbo->map, &not_used);
}
Expand Down Expand Up @@ -390,6 +420,7 @@ static int vmw_bo_init(struct vmw_private *dev_priv,
BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
vmw_bo->tbo.priority = 3;
vmw_bo->res_tree = RB_ROOT;
xa_init(&vmw_bo->detached_resources);

params->size = ALIGN(params->size, PAGE_SIZE);
drm_gem_private_object_init(vdev, &vmw_bo->tbo.base, params->size);
Expand Down Expand Up @@ -654,52 +685,6 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
dma_fence_put(&fence->base);
}


/**
* vmw_dumb_create - Create a dumb kms buffer
*
* @file_priv: Pointer to a struct drm_file identifying the caller.
* @dev: Pointer to the drm device.
* @args: Pointer to a struct drm_mode_create_dumb structure
* Return: Zero on success, negative error code on failure.
*
* This is a driver callback for the core drm create_dumb functionality.
* Note that this is very similar to the vmw_bo_alloc ioctl, except
* that the arguments have a different format.
*/
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_bo *vbo;
int cpp = DIV_ROUND_UP(args->bpp, 8);
int ret;

switch (cpp) {
case 1: /* DRM_FORMAT_C8 */
case 2: /* DRM_FORMAT_RGB565 */
case 4: /* DRM_FORMAT_XRGB8888 */
break;
default:
/*
* Dumb buffers don't allow anything else.
* This is tested via IGT's dumb_buffers
*/
return -EINVAL;
}

args->pitch = args->width * cpp;
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);

ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
args->size, &args->handle,
&vbo);
/* drop reference from allocate - handle holds it now */
drm_gem_object_put(&vbo->tbo.base);
return ret;
}

/**
* vmw_bo_swap_notify - swapout notify callback.
*
Expand Down Expand Up @@ -853,3 +838,43 @@ void vmw_bo_placement_set_default_accelerated(struct vmw_bo *bo)

vmw_bo_placement_set(bo, domain, domain);
}

void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
{
xa_store(&vbo->detached_resources, (unsigned long)res, res, GFP_KERNEL);
}

void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
{
xa_erase(&vbo->detached_resources, (unsigned long)res);
}

struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo)
{
unsigned long index;
struct vmw_resource *res = NULL;
struct vmw_surface *surf = NULL;
struct rb_node *rb_itr = vbo->res_tree.rb_node;

if (vbo->is_dumb && vbo->dumb_surface) {
res = &vbo->dumb_surface->res;
goto out;
}

xa_for_each(&vbo->detached_resources, index, res) {
if (res->func->res_type == vmw_res_surface)
goto out;
}

for (rb_itr = rb_first(&vbo->res_tree); rb_itr;
rb_itr = rb_next(rb_itr)) {
res = rb_entry(rb_itr, struct vmw_resource, mob_node);
if (res->func->res_type == vmw_res_surface)
goto out;
}

out:
if (res)
surf = vmw_res_to_srf(res);
return surf;
}
15 changes: 14 additions & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
* Copyright 2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2023-2024 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
Expand Down Expand Up @@ -35,11 +36,13 @@

#include <linux/rbtree_types.h>
#include <linux/types.h>
#include <linux/xarray.h>

struct vmw_bo_dirty;
struct vmw_fence_obj;
struct vmw_private;
struct vmw_resource;
struct vmw_surface;

enum vmw_bo_domain {
VMW_BO_DOMAIN_SYS = BIT(0),
Expand Down Expand Up @@ -85,11 +88,15 @@ struct vmw_bo {

struct rb_root res_tree;
u32 res_prios[TTM_MAX_BO_PRIORITY];
struct xarray detached_resources;

atomic_t cpu_writers;
/* Not ref-counted. Protected by binding_mutex */
struct vmw_resource *dx_query_ctx;
struct vmw_bo_dirty *dirty;

bool is_dumb;
struct vmw_surface *dumb_surface;
};

void vmw_bo_placement_set(struct vmw_bo *bo, u32 domain, u32 busy_domain);
Expand Down Expand Up @@ -124,15 +131,21 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
struct vmw_fence_obj *fence);

void *vmw_bo_map_and_cache(struct vmw_bo *vbo);
void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size);
void vmw_bo_unmap(struct vmw_bo *vbo);

void vmw_bo_move_notify(struct ttm_buffer_object *bo,
struct ttm_resource *mem);
void vmw_bo_swap_notify(struct ttm_buffer_object *bo);

void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo);

int vmw_user_bo_lookup(struct drm_file *filp,
u32 handle,
struct vmw_bo **out);

/**
* vmw_bo_adjust_prio - Adjust the buffer object eviction priority
* according to attached resources
Expand Down
40 changes: 31 additions & 9 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
Expand Down Expand Up @@ -762,6 +763,26 @@ extern int vmw_gmr_bind(struct vmw_private *dev_priv,
int gmr_id);
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);

/**
* User handles
*/
struct vmw_user_object {
struct vmw_surface *surface;
struct vmw_bo *buffer;
};

int vmw_user_object_lookup(struct vmw_private *dev_priv, struct drm_file *filp,
u32 handle, struct vmw_user_object *uo);
struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo);
void vmw_user_object_unref(struct vmw_user_object *uo);
bool vmw_user_object_is_null(struct vmw_user_object *uo);
struct vmw_surface *vmw_user_object_surface(struct vmw_user_object *uo);
struct vmw_bo *vmw_user_object_buffer(struct vmw_user_object *uo);
void *vmw_user_object_map(struct vmw_user_object *uo);
void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size);
void vmw_user_object_unmap(struct vmw_user_object *uo);
bool vmw_user_object_is_mapped(struct vmw_user_object *uo);

/**
* Resource utilities - vmwgfx_resource.c
*/
Expand All @@ -776,11 +797,6 @@ extern int vmw_resource_validate(struct vmw_resource *res, bool intr,
extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible,
bool no_backup);
extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
struct drm_file *filp,
uint32_t handle,
struct vmw_surface **out_surf,
struct vmw_bo **out_buf);
extern int vmw_user_resource_lookup_handle(
struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
Expand Down Expand Up @@ -1057,9 +1073,6 @@ int vmw_kms_suspend(struct drm_device *dev);
int vmw_kms_resume(struct drm_device *dev);
void vmw_kms_lost_device(struct drm_device *dev);

int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
extern void vmw_resource_unpin(struct vmw_resource *res);
extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
Expand Down Expand Up @@ -1176,6 +1189,15 @@ extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev,
int vmw_gb_surface_define(struct vmw_private *dev_priv,
const struct vmw_surface_metadata *req,
struct vmw_surface **srf_out);
struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle);
u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle);
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);

/*
* Shader management - vmwgfx_shader.c
Expand Down
Loading

0 comments on commit d6667f0

Please sign in to comment.