Skip to content

Commit

Permalink
drm/vmwgfx: Implement virtual crc generation
Browse files Browse the repository at this point in the history
crc checksums are used to validate the output. Normally they're part
of the actual display hardware but on virtual stack there's nothing
to automatically generate them.

Implement crc generation for the vmwgfx stack. This works only on
screen targets, where it's possibly to easily make sure that the
guest side contents of the surface matches the host sides output.

Just like the vblank support, crc generation can only be enabled via:
guestinfo.vmwgfx.vkms_enable = "TRUE"
option in the vmx file.

Makes IGT's kms_pipe_crc_basic pass and allows a huge number of other
IGT tests which require CRC generation of the output to actually run
on vmwgfx. Makes it possible to actually validate a lof of the kms and
drm functionality with vmwgfx.

Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Acked-by: Martin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240412025511.78553-3-zack.rusin@broadcom.com
  • Loading branch information
zackr committed Apr 15, 2024
1 parent cd2eb57 commit 7b00620
Show file tree
Hide file tree
Showing 8 changed files with 553 additions and 35 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,7 @@ static void vmw_driver_unload(struct drm_device *dev)

vmw_svga_disable(dev_priv);

vmw_vkms_cleanup(dev_priv);
vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv);

Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ struct vmw_private {
uint32 *devcaps;

bool vkms_enabled;
struct workqueue_struct *crc_workq;

/*
* mksGuestStat instance-descriptor and pid arrays
Expand Down Expand Up @@ -811,6 +812,7 @@ void vmw_resource_mob_attach(struct vmw_resource *res);
void vmw_resource_mob_detach(struct vmw_resource *res);
void vmw_resource_dirty_update(struct vmw_resource *res, pgoff_t start,
pgoff_t end);
int vmw_resource_clean(struct vmw_resource *res);
int vmw_resources_clean(struct vmw_bo *vbo, pgoff_t start,
pgoff_t end, pgoff_t *num_prefault);

Expand Down
31 changes: 28 additions & 3 deletions drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@

void vmw_du_init(struct vmw_display_unit *du)
{
hrtimer_init(&du->vkms.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
du->vkms.timer.function = &vmw_vkms_vblank_simulate;
vmw_vkms_crtc_init(&du->crtc);
}

void vmw_du_cleanup(struct vmw_display_unit *du)
{
struct vmw_private *dev_priv = vmw_priv(du->primary.dev);
hrtimer_cancel(&du->vkms.timer);

vmw_vkms_crtc_cleanup(&du->crtc);
drm_plane_cleanup(&du->primary);
if (vmw_cmd_supported(dev_priv))
drm_plane_cleanup(&du->cursor.base);
Expand Down Expand Up @@ -963,6 +963,7 @@ int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
vmw_vkms_crtc_atomic_begin(crtc, state);
}

/**
Expand Down Expand Up @@ -2029,6 +2030,29 @@ vmw_kms_create_hotplug_mode_update_property(struct vmw_private *dev_priv)
"hotplug_mode_update", 0, 1);
}

static void
vmw_atomic_commit_tail(struct drm_atomic_state *old_state)
{
struct vmw_private *vmw = vmw_priv(old_state->dev);
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
int i;

drm_atomic_helper_commit_tail(old_state);

if (vmw->vkms_enabled) {
for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
(void)old_crtc_state;
flush_work(&du->vkms.crc_generator_work);
}
}
}

static const struct drm_mode_config_helper_funcs vmw_mode_config_helpers = {
.atomic_commit_tail = vmw_atomic_commit_tail,
};

int vmw_kms_init(struct vmw_private *dev_priv)
{
struct drm_device *dev = &dev_priv->drm;
Expand All @@ -2048,6 +2072,7 @@ int vmw_kms_init(struct vmw_private *dev_priv)
dev->mode_config.max_width = dev_priv->texture_max_width;
dev->mode_config.max_height = dev_priv->texture_max_height;
dev->mode_config.preferred_depth = dev_priv->assume_16bpp ? 16 : 32;
dev->mode_config.helper_private = &vmw_mode_config_helpers;

drm_mode_create_suggested_offset_properties(dev);
vmw_kms_create_hotplug_mode_update_property(dev_priv);
Expand Down
15 changes: 14 additions & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,22 @@ struct vmw_display_unit {
int set_gui_y;

struct {
struct work_struct crc_generator_work;
struct hrtimer timer;
ktime_t period_ns;
struct drm_pending_vblank_event *event;

/* protects concurrent access to the vblank handler */
atomic_t atomic_lock;
/* protected by @atomic_lock */
bool crc_enabled;
struct vmw_surface *surface;

/* protects concurrent access to the crc worker */
spinlock_t crc_state_lock;
/* protected by @crc_state_lock */
bool crc_pending;
u64 frame_start;
u64 frame_end;
} vkms;
};

Expand Down
32 changes: 20 additions & 12 deletions drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,22 @@ void vmw_resource_dirty_update(struct vmw_resource *res, pgoff_t start,
end << PAGE_SHIFT);
}

int vmw_resource_clean(struct vmw_resource *res)
{
int ret = 0;

if (res->res_dirty) {
if (!res->func->clean)
return -EINVAL;

ret = res->func->clean(res);
if (ret)
return ret;
res->res_dirty = false;
}
return ret;
}

/**
* vmw_resources_clean - Clean resources intersecting a mob range
* @vbo: The mob buffer object
Expand All @@ -1080,6 +1096,7 @@ int vmw_resources_clean(struct vmw_bo *vbo, pgoff_t start,
unsigned long res_start = start << PAGE_SHIFT;
unsigned long res_end = end << PAGE_SHIFT;
unsigned long last_cleaned = 0;
int ret;

/*
* Find the resource with lowest backup_offset that intersects the
Expand All @@ -1106,18 +1123,9 @@ int vmw_resources_clean(struct vmw_bo *vbo, pgoff_t start,
* intersecting the range.
*/
while (found) {
if (found->res_dirty) {
int ret;

if (!found->func->clean)
return -EINVAL;

ret = found->func->clean(found);
if (ret)
return ret;

found->res_dirty = false;
}
ret = vmw_resource_clean(found);
if (ret)
return ret;
last_cleaned = found->guest_memory_offset + found->guest_memory_size;
cur = rb_next(&found->mob_node);
if (!cur)
Expand Down
22 changes: 15 additions & 7 deletions drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,6 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
crtc->x, crtc->y);
}


static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
{
}

static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
Expand Down Expand Up @@ -783,6 +778,9 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
.enable_vblank = vmw_vkms_enable_vblank,
.disable_vblank = vmw_vkms_disable_vblank,
.get_vblank_timestamp = vmw_vkms_get_vblank_timestamp,
.get_crc_sources = vmw_vkms_get_crc_sources,
.set_crc_source = vmw_vkms_set_crc_source,
.verify_crc_source = vmw_vkms_verify_crc_source,
};


Expand Down Expand Up @@ -1414,6 +1412,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
vmw_fence_obj_unreference(&fence);
}

static void
vmw_stdu_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
struct vmw_private *vmw = vmw_priv(crtc->dev);
struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);

if (vmw->vkms_enabled)
vmw_vkms_set_crc_surface(crtc, stdu->display_srf);
vmw_vkms_crtc_atomic_flush(crtc, state);
}

static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
Expand Down Expand Up @@ -1454,11 +1463,10 @@ drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = {
};

static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
.prepare = vmw_stdu_crtc_helper_prepare,
.mode_set_nofb = vmw_stdu_crtc_mode_set_nofb,
.atomic_check = vmw_du_crtc_atomic_check,
.atomic_begin = vmw_du_crtc_atomic_begin,
.atomic_flush = vmw_vkms_crtc_atomic_flush,
.atomic_flush = vmw_stdu_crtc_atomic_flush,
.atomic_enable = vmw_vkms_crtc_atomic_enable,
.atomic_disable = vmw_stdu_crtc_atomic_disable,
};
Expand Down
Loading

0 comments on commit 7b00620

Please sign in to comment.