Skip to content

Commit d6667f0

Browse files
committed
drm/vmwgfx: Fix handling of dumb buffers
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 <[email protected]> Fixes: b32233a ("drm/vmwgfx: Fix prime import/export") Cc: Broadcom internal kernel review list <[email protected]> Cc: [email protected] Cc: <[email protected]> # v6.9+ Reviewed-by: Maaz Mombasawala <[email protected]> Reviewed-by: Martin Krastev <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 09f34a0 commit d6667f0

File tree

12 files changed

+740
-502
lines changed

12 files changed

+740
-502
lines changed

drivers/gpu/drm/vmwgfx/vmw_surface_cache.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
12
/**********************************************************
2-
* Copyright 2021 VMware, Inc.
3-
* SPDX-License-Identifier: GPL-2.0 OR MIT
3+
*
4+
* Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
5+
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
46
*
57
* Permission is hereby granted, free of charge, to any person
68
* obtaining a copy of this software and associated documentation
@@ -31,6 +33,10 @@
3133

3234
#include <drm/vmwgfx_drm.h>
3335

36+
#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32)
37+
#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
38+
((svga3d_flags) & ((uint64_t)U32_MAX))
39+
3440
static inline u32 clamped_umul32(u32 a, u32 b)
3541
{
3642
uint64_t tmp = (uint64_t) a*b;

drivers/gpu/drm/vmwgfx/vmwgfx_bo.c

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// SPDX-License-Identifier: GPL-2.0 OR MIT
22
/**************************************************************************
33
*
4-
* Copyright © 2011-2023 VMware, Inc., Palo Alto, CA., USA
5-
* All Rights Reserved.
4+
* Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term
5+
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
66
*
77
* Permission is hereby granted, free of charge, to any person obtaining a
88
* copy of this software and associated documentation files (the
@@ -28,15 +28,39 @@
2828

2929
#include "vmwgfx_bo.h"
3030
#include "vmwgfx_drv.h"
31-
31+
#include "vmwgfx_resource_priv.h"
3232

3333
#include <drm/ttm/ttm_placement.h>
3434

3535
static void vmw_bo_release(struct vmw_bo *vbo)
3636
{
37+
struct vmw_resource *res;
38+
3739
WARN_ON(vbo->tbo.base.funcs &&
3840
kref_read(&vbo->tbo.base.refcount) != 0);
3941
vmw_bo_unmap(vbo);
42+
43+
xa_destroy(&vbo->detached_resources);
44+
WARN_ON(vbo->is_dumb && !vbo->dumb_surface);
45+
if (vbo->is_dumb && vbo->dumb_surface) {
46+
res = &vbo->dumb_surface->res;
47+
WARN_ON(vbo != res->guest_memory_bo);
48+
WARN_ON(!res->guest_memory_bo);
49+
if (res->guest_memory_bo) {
50+
/* Reserve and switch the backing mob. */
51+
mutex_lock(&res->dev_priv->cmdbuf_mutex);
52+
(void)vmw_resource_reserve(res, false, true);
53+
vmw_resource_mob_detach(res);
54+
if (res->coherent)
55+
vmw_bo_dirty_release(res->guest_memory_bo);
56+
res->guest_memory_bo = NULL;
57+
res->guest_memory_offset = 0;
58+
vmw_resource_unreserve(res, false, false, false, NULL,
59+
0);
60+
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
61+
}
62+
vmw_surface_unreference(&vbo->dumb_surface);
63+
}
4064
drm_gem_object_release(&vbo->tbo.base);
4165
}
4266

@@ -325,6 +349,11 @@ void vmw_bo_pin_reserved(struct vmw_bo *vbo, bool pin)
325349
*
326350
*/
327351
void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
352+
{
353+
return vmw_bo_map_and_cache_size(vbo, vbo->tbo.base.size);
354+
}
355+
356+
void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size)
328357
{
329358
struct ttm_buffer_object *bo = &vbo->tbo;
330359
bool not_used;
@@ -335,9 +364,10 @@ void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
335364
if (virtual)
336365
return virtual;
337366

338-
ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map);
367+
ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vbo->map);
339368
if (ret)
340-
DRM_ERROR("Buffer object map failed: %d.\n", ret);
369+
DRM_ERROR("Buffer object map failed: %d (size: bo = %zu, map = %zu).\n",
370+
ret, bo->base.size, size);
341371

342372
return ttm_kmap_obj_virtual(&vbo->map, &not_used);
343373
}
@@ -390,6 +420,7 @@ static int vmw_bo_init(struct vmw_private *dev_priv,
390420
BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
391421
vmw_bo->tbo.priority = 3;
392422
vmw_bo->res_tree = RB_ROOT;
423+
xa_init(&vmw_bo->detached_resources);
393424

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

657-
658-
/**
659-
* vmw_dumb_create - Create a dumb kms buffer
660-
*
661-
* @file_priv: Pointer to a struct drm_file identifying the caller.
662-
* @dev: Pointer to the drm device.
663-
* @args: Pointer to a struct drm_mode_create_dumb structure
664-
* Return: Zero on success, negative error code on failure.
665-
*
666-
* This is a driver callback for the core drm create_dumb functionality.
667-
* Note that this is very similar to the vmw_bo_alloc ioctl, except
668-
* that the arguments have a different format.
669-
*/
670-
int vmw_dumb_create(struct drm_file *file_priv,
671-
struct drm_device *dev,
672-
struct drm_mode_create_dumb *args)
673-
{
674-
struct vmw_private *dev_priv = vmw_priv(dev);
675-
struct vmw_bo *vbo;
676-
int cpp = DIV_ROUND_UP(args->bpp, 8);
677-
int ret;
678-
679-
switch (cpp) {
680-
case 1: /* DRM_FORMAT_C8 */
681-
case 2: /* DRM_FORMAT_RGB565 */
682-
case 4: /* DRM_FORMAT_XRGB8888 */
683-
break;
684-
default:
685-
/*
686-
* Dumb buffers don't allow anything else.
687-
* This is tested via IGT's dumb_buffers
688-
*/
689-
return -EINVAL;
690-
}
691-
692-
args->pitch = args->width * cpp;
693-
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);
694-
695-
ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
696-
args->size, &args->handle,
697-
&vbo);
698-
/* drop reference from allocate - handle holds it now */
699-
drm_gem_object_put(&vbo->tbo.base);
700-
return ret;
701-
}
702-
703688
/**
704689
* vmw_bo_swap_notify - swapout notify callback.
705690
*
@@ -853,3 +838,43 @@ void vmw_bo_placement_set_default_accelerated(struct vmw_bo *bo)
853838

854839
vmw_bo_placement_set(bo, domain, domain);
855840
}
841+
842+
void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
843+
{
844+
xa_store(&vbo->detached_resources, (unsigned long)res, res, GFP_KERNEL);
845+
}
846+
847+
void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
848+
{
849+
xa_erase(&vbo->detached_resources, (unsigned long)res);
850+
}
851+
852+
struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo)
853+
{
854+
unsigned long index;
855+
struct vmw_resource *res = NULL;
856+
struct vmw_surface *surf = NULL;
857+
struct rb_node *rb_itr = vbo->res_tree.rb_node;
858+
859+
if (vbo->is_dumb && vbo->dumb_surface) {
860+
res = &vbo->dumb_surface->res;
861+
goto out;
862+
}
863+
864+
xa_for_each(&vbo->detached_resources, index, res) {
865+
if (res->func->res_type == vmw_res_surface)
866+
goto out;
867+
}
868+
869+
for (rb_itr = rb_first(&vbo->res_tree); rb_itr;
870+
rb_itr = rb_next(rb_itr)) {
871+
res = rb_entry(rb_itr, struct vmw_resource, mob_node);
872+
if (res->func->res_type == vmw_res_surface)
873+
goto out;
874+
}
875+
876+
out:
877+
if (res)
878+
surf = vmw_res_to_srf(res);
879+
return surf;
880+
}

drivers/gpu/drm/vmwgfx/vmwgfx_bo.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
22
/**************************************************************************
33
*
4-
* Copyright 2023 VMware, Inc., Palo Alto, CA., USA
4+
* Copyright (c) 2023-2024 Broadcom. All Rights Reserved. The term
5+
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
56
*
67
* Permission is hereby granted, free of charge, to any person obtaining a
78
* copy of this software and associated documentation files (the
@@ -35,11 +36,13 @@
3536

3637
#include <linux/rbtree_types.h>
3738
#include <linux/types.h>
39+
#include <linux/xarray.h>
3840

3941
struct vmw_bo_dirty;
4042
struct vmw_fence_obj;
4143
struct vmw_private;
4244
struct vmw_resource;
45+
struct vmw_surface;
4346

4447
enum vmw_bo_domain {
4548
VMW_BO_DOMAIN_SYS = BIT(0),
@@ -85,11 +88,15 @@ struct vmw_bo {
8588

8689
struct rb_root res_tree;
8790
u32 res_prios[TTM_MAX_BO_PRIORITY];
91+
struct xarray detached_resources;
8892

8993
atomic_t cpu_writers;
9094
/* Not ref-counted. Protected by binding_mutex */
9195
struct vmw_resource *dx_query_ctx;
9296
struct vmw_bo_dirty *dirty;
97+
98+
bool is_dumb;
99+
struct vmw_surface *dumb_surface;
93100
};
94101

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

126133
void *vmw_bo_map_and_cache(struct vmw_bo *vbo);
134+
void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size);
127135
void vmw_bo_unmap(struct vmw_bo *vbo);
128136

129137
void vmw_bo_move_notify(struct ttm_buffer_object *bo,
130138
struct ttm_resource *mem);
131139
void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
132140

141+
void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
142+
void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
143+
struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo);
144+
133145
int vmw_user_bo_lookup(struct drm_file *filp,
134146
u32 handle,
135147
struct vmw_bo **out);
148+
136149
/**
137150
* vmw_bo_adjust_prio - Adjust the buffer object eviction priority
138151
* according to attached resources

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
22
/**************************************************************************
33
*
4-
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
4+
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
5+
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
56
*
67
* Permission is hereby granted, free of charge, to any person obtaining a
78
* copy of this software and associated documentation files (the
@@ -762,6 +763,26 @@ extern int vmw_gmr_bind(struct vmw_private *dev_priv,
762763
int gmr_id);
763764
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
764765

766+
/**
767+
* User handles
768+
*/
769+
struct vmw_user_object {
770+
struct vmw_surface *surface;
771+
struct vmw_bo *buffer;
772+
};
773+
774+
int vmw_user_object_lookup(struct vmw_private *dev_priv, struct drm_file *filp,
775+
u32 handle, struct vmw_user_object *uo);
776+
struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo);
777+
void vmw_user_object_unref(struct vmw_user_object *uo);
778+
bool vmw_user_object_is_null(struct vmw_user_object *uo);
779+
struct vmw_surface *vmw_user_object_surface(struct vmw_user_object *uo);
780+
struct vmw_bo *vmw_user_object_buffer(struct vmw_user_object *uo);
781+
void *vmw_user_object_map(struct vmw_user_object *uo);
782+
void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size);
783+
void vmw_user_object_unmap(struct vmw_user_object *uo);
784+
bool vmw_user_object_is_mapped(struct vmw_user_object *uo);
785+
765786
/**
766787
* Resource utilities - vmwgfx_resource.c
767788
*/
@@ -776,11 +797,6 @@ extern int vmw_resource_validate(struct vmw_resource *res, bool intr,
776797
extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible,
777798
bool no_backup);
778799
extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
779-
extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
780-
struct drm_file *filp,
781-
uint32_t handle,
782-
struct vmw_surface **out_surf,
783-
struct vmw_bo **out_buf);
784800
extern int vmw_user_resource_lookup_handle(
785801
struct vmw_private *dev_priv,
786802
struct ttm_object_file *tfile,
@@ -1057,9 +1073,6 @@ int vmw_kms_suspend(struct drm_device *dev);
10571073
int vmw_kms_resume(struct drm_device *dev);
10581074
void vmw_kms_lost_device(struct drm_device *dev);
10591075

1060-
int vmw_dumb_create(struct drm_file *file_priv,
1061-
struct drm_device *dev,
1062-
struct drm_mode_create_dumb *args);
10631076
extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
10641077
extern void vmw_resource_unpin(struct vmw_resource *res);
10651078
extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
@@ -1176,6 +1189,15 @@ extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev,
11761189
int vmw_gb_surface_define(struct vmw_private *dev_priv,
11771190
const struct vmw_surface_metadata *req,
11781191
struct vmw_surface **srf_out);
1192+
struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw,
1193+
struct vmw_bo *bo,
1194+
u32 handle);
1195+
u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw,
1196+
struct vmw_bo *bo,
1197+
u32 handle);
1198+
int vmw_dumb_create(struct drm_file *file_priv,
1199+
struct drm_device *dev,
1200+
struct drm_mode_create_dumb *args);
11791201

11801202
/*
11811203
* Shader management - vmwgfx_shader.c

0 commit comments

Comments
 (0)