Skip to content

Commit

Permalink
drm/vmwgfx: Detect old user-space drivers and set up legacy emulation v2
Browse files Browse the repository at this point in the history
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: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
  • Loading branch information
Thomas Hellstrom committed Feb 5, 2014
1 parent d5bde95 commit a6fc955
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 16 deletions.
24 changes: 24 additions & 0 deletions drivers/gpu/drm/vmwgfx/svga3d_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
93 changes: 77 additions & 16 deletions drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 &
Expand All @@ -69,17 +80,26 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
break;
}
case DRM_VMW_PARAM_MAX_SURF_MEMORY:
param->value = dev_priv->memory_size;
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:
Expand All @@ -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)
Expand All @@ -104,48 +156,57 @@ 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);
}

ret = copy_to_user(buffer, bounce, size);
if (ret)
ret = -EFAULT;
out_err:
vfree(bounce);

if (unlikely(ret != 0))
Expand Down

0 comments on commit a6fc955

Please sign in to comment.