Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6fc955f authored by Thomas Hellstrom's avatar Thomas Hellstrom
Browse files

drm/vmwgfx: Detect old user-space drivers and set up legacy emulation v2



GB aware mesa userspace drivers are detected by the fact that they are
calling the vmw getparam ioctl querying DRM_VMW_PARAM_HW_CAPS to detect
whether the device is Guest-backed object capable. For other drivers,
lie about hardware version and send the 3D capabilities in a format they
expect.

v2:
Use DRM_VMW_PARAM_MAX_MOB_MEMORY to detect gb awareness,
Make sure we don't ovwerwrite bounce buffer or write past user-space buffer
indicated size.

Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarJakob Bornecrantz <jakob@vmware.com>
parent d5bde956
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -2583,4 +2583,28 @@ typedef union {
   float  f;
} SVGA3dDevCapResult;

typedef enum {
   SVGA3DCAPS_RECORD_UNKNOWN        = 0,
   SVGA3DCAPS_RECORD_DEVCAPS_MIN    = 0x100,
   SVGA3DCAPS_RECORD_DEVCAPS        = 0x100,
   SVGA3DCAPS_RECORD_DEVCAPS_MAX    = 0x1ff,
} SVGA3dCapsRecordType;

typedef
struct SVGA3dCapsRecordHeader {
   uint32 length;
   SVGA3dCapsRecordType type;
}
SVGA3dCapsRecordHeader;

typedef
struct SVGA3dCapsRecord {
   SVGA3dCapsRecordHeader header;
   uint32 data[1];
}
SVGA3dCapsRecord;


typedef uint32 SVGA3dCapPair[2];

#endif /* _SVGA3D_REG_H_ */
+77 −16
Original line number Diff line number Diff line
@@ -29,12 +29,18 @@
#include <drm/vmwgfx_drm.h>
#include "vmwgfx_kms.h"

struct svga_3d_compat_cap {
	SVGA3dCapsRecordHeader header;
	SVGA3dCapPair pairs[SVGA3D_DEVCAP_MAX];
};

int vmw_getparam_ioctl(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
{
	struct vmw_private *dev_priv = vmw_priv(dev);
	struct drm_vmw_getparam_arg *param =
	    (struct drm_vmw_getparam_arg *)data;
	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);

	switch (param->param) {
	case DRM_VMW_PARAM_NUM_STREAMS:
@@ -60,6 +66,11 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
		__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
		const struct vmw_fifo_state *fifo = &dev_priv->fifo;

		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) {
			param->value = SVGA3D_HWVERSION_WS8_B1;
			break;
		}

		param->value =
			ioread32(fifo_mem +
				 ((fifo->capabilities &
@@ -69,17 +80,26 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
		break;
	}
	case DRM_VMW_PARAM_MAX_SURF_MEMORY:
		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&
		    !vmw_fp->gb_aware)
			param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2;
		else
			param->value = dev_priv->memory_size;
		break;
	case DRM_VMW_PARAM_3D_CAPS_SIZE:
		if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS)
			param->value = SVGA3D_DEVCAP_MAX;
		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&
		    vmw_fp->gb_aware)
			param->value = SVGA3D_DEVCAP_MAX * sizeof(uint32_t);
		else if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS)
			param->value = sizeof(struct svga_3d_compat_cap) +
				sizeof(uint32_t);
		else
			param->value = (SVGA_FIFO_3D_CAPS_LAST -
					SVGA_FIFO_3D_CAPS + 1);
		param->value *= sizeof(uint32_t);
					SVGA_FIFO_3D_CAPS + 1) *
				sizeof(uint32_t);
		break;
	case DRM_VMW_PARAM_MAX_MOB_MEMORY:
		vmw_fp->gb_aware = true;
		param->value = dev_priv->max_mob_pages * PAGE_SIZE;
		break;
	default:
@@ -91,6 +111,38 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
	return 0;
}

static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce,
			       size_t size)
{
	struct svga_3d_compat_cap *compat_cap =
		(struct svga_3d_compat_cap *) bounce;
	unsigned int i;
	size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs);
	unsigned int max_size;

	if (size < pair_offset)
		return -EINVAL;

	max_size = (size - pair_offset) / sizeof(SVGA3dCapPair);

	if (max_size > SVGA3D_DEVCAP_MAX)
		max_size = SVGA3D_DEVCAP_MAX;

	compat_cap->header.length =
		(pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32);
	compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS;

	mutex_lock(&dev_priv->hw_mutex);
	for (i = 0; i < max_size; ++i) {
		vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
		compat_cap->pairs[i][0] = i;
		compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
	}
	mutex_unlock(&dev_priv->hw_mutex);

	return 0;
}


int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
@@ -104,41 +156,49 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
	void *bounce;
	int ret;
	bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);

	if (unlikely(arg->pad64 != 0)) {
		DRM_ERROR("Illegal GET_3D_CAP argument.\n");
		return -EINVAL;
	}

	if (gb_objects)
		size = SVGA3D_DEVCAP_MAX;
	if (gb_objects && vmw_fp->gb_aware)
		size = SVGA3D_DEVCAP_MAX * sizeof(uint32_t);
	else if (gb_objects)
		size = sizeof(struct svga_3d_compat_cap) + sizeof(uint32_t);
	else
		size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1);

	size *= sizeof(uint32_t);
		size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) *
			sizeof(uint32_t);

	if (arg->max_size < size)
		size = arg->max_size;

	bounce = vmalloc(size);
	bounce = vzalloc(size);
	if (unlikely(bounce == NULL)) {
		DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");
		return -ENOMEM;
	}

	if (gb_objects) {
		int i;
	if (gb_objects && vmw_fp->gb_aware) {
		int i, num;
		uint32_t *bounce32 = (uint32_t *) bounce;

		num = size / sizeof(uint32_t);
		if (num > SVGA3D_DEVCAP_MAX)
			num = SVGA3D_DEVCAP_MAX;

		mutex_lock(&dev_priv->hw_mutex);
		for (i = 0; i < SVGA3D_DEVCAP_MAX; ++i) {
		for (i = 0; i < num; ++i) {
			vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
			*bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
		}
		mutex_unlock(&dev_priv->hw_mutex);

	} else if (gb_objects) {
		ret = vmw_fill_compat_cap(dev_priv, bounce, size);
		if (unlikely(ret != 0))
			goto out_err;
	} else {

		fifo_mem = dev_priv->mmio_virt;
		memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
	}
@@ -146,6 +206,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
	ret = copy_to_user(buffer, bounce, size);
	if (ret)
		ret = -EFAULT;
out_err:
	vfree(bounce);

	if (unlikely(ret != 0))