drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
Extension
.c
Size
15153 bytes
Lines
604
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (vmw_surface_sync(vmw, surf)) {
			drm_warn(
				crtc->dev,
				"CRC worker wasn't able to sync the crc surface!\n");
			return;
		}

		compute_crc(crtc, surf, &crc32);
		vmw_surface_unreference(&surf);
	}

	spin_lock_irq(&du->vkms.crc_state_lock);
	frame_start = du->vkms.frame_start;
	frame_end = du->vkms.frame_end;
	du->vkms.frame_start = 0;
	du->vkms.frame_end = 0;
	du->vkms.crc_pending = false;
	spin_unlock_irq(&du->vkms.crc_state_lock);

	/*
	 * The worker can fall behind the vblank hrtimer, make sure we catch up.
	 */
	while (frame_start <= frame_end)
		drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
}

bool
vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc)
{
	struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
	struct vmw_private *vmw = vmw_priv(crtc->dev);
	bool has_surface = false;
	bool locked, ret;

	locked = vmw_vkms_vblank_trylock(crtc);
	ret = drm_crtc_handle_vblank(crtc);
	WARN_ON(!ret);
	if (!locked)
		return true;
	has_surface = du->vkms.surface != NULL;
	vmw_vkms_unlock(crtc);

	if (du->vkms.crc_enabled && has_surface) {
		u64 frame = drm_crtc_accurate_vblank_count(crtc);

		spin_lock(&du->vkms.crc_state_lock);
		if (!du->vkms.crc_pending)
			du->vkms.frame_start = frame;
		else
			drm_dbg_driver(crtc->dev,
				       "crc worker falling behind, frame_start: %llu, frame_end: %llu\n",
				       du->vkms.frame_start, frame);
		du->vkms.frame_end = frame;
		du->vkms.crc_pending = true;
		spin_unlock(&du->vkms.crc_state_lock);

		ret = queue_work(vmw->crc_workq, &du->vkms.crc_generator_work);
		if (!ret)
			drm_dbg_driver(crtc->dev, "Composer worker already queued\n");
	}

	return true;
}

void
vmw_vkms_init(struct vmw_private *vmw)
{
	char buffer[64];
	const size_t max_buf_len = sizeof(buffer) - 1;
	size_t buf_len = max_buf_len;
	int ret;

	vmw->vkms_enabled = false;

	ret = vmw_host_get_guestinfo(GUESTINFO_VBLANK, buffer, &buf_len);
	if (ret || buf_len > max_buf_len)
		return;
	buffer[buf_len] = '\0';

	ret = kstrtobool(buffer, &vmw->vkms_enabled);
	if (!ret && vmw->vkms_enabled) {
		ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
		vmw->vkms_enabled = (ret == 0);
	}

	vmw->crc_workq = alloc_ordered_workqueue("vmwgfx_crc_generator", 0);
	if (!vmw->crc_workq) {
		drm_warn(&vmw->drm, "crc workqueue allocation failed. Disabling vkms.");
		vmw->vkms_enabled = false;
	}

Annotation

Implementation Notes