Commit 7b006203 authored by Zack Rusin's avatar Zack Rusin
Browse files

drm/vmwgfx: Implement virtual crc generation



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: default avatarZack Rusin <zack.rusin@broadcom.com>
Acked-by: default avatarMartin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240412025511.78553-3-zack.rusin@broadcom.com
parent cd2eb57d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -616,6 +616,7 @@ struct vmw_private {
	uint32 *devcaps;

	bool vkms_enabled;
	struct workqueue_struct *crc_workq;

	/*
	 * mksGuestStat instance-descriptor and pid arrays
@@ -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);

+28 −3
Original line number Diff line number Diff line
@@ -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);
@@ -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);
}

/**
@@ -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;
@@ -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);
+14 −1
Original line number Diff line number Diff line
@@ -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;
};

+20 −12
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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);
		ret = vmw_resource_clean(found);
		if (ret)
			return ret;

			found->res_dirty = false;
		}
		last_cleaned = found->guest_memory_offset + found->guest_memory_size;
		cur = rb_next(&found->mob_node);
		if (!cur)
Loading