Merge branch 'drm-vmware-staging' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2009 21:19:31 +0000 (13:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2009 21:19:31 +0000 (13:19 -0800)
* 'drm-vmware-staging' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/vmwgfx: Add DRM driver for VMware Virtual GPU
  drm/vmwgfx: Add svga headers for vmwgfx driver
  drm/ttm: Add more driver type enums

28 files changed:
drivers/gpu/drm/Makefile
drivers/gpu/drm/vmwgfx/Kconfig [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/Makefile [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/svga3d_reg.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/svga_escape.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/svga_overlay.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/svga_reg.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/svga_types.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_reg.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c [new file with mode: 0644]
drivers/staging/Kconfig
include/drm/Kbuild
include/drm/ttm/ttm_object.h
include/drm/vmwgfx_drm.h [new file with mode: 0644]

index 470ef6779db33d11e2bcbc60610f8671c34d10ef..39c5aa75b8f119eb6cc3263e44bc592ef25b9f30 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_I830)        += i830/
 obj-$(CONFIG_DRM_I915)  += i915/
 obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
+obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)  +=via/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-y                  += i2c/
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig
new file mode 100644 (file)
index 0000000..f20b8bc
--- /dev/null
@@ -0,0 +1,13 @@
+config DRM_VMWGFX
+       tristate "DRM driver for VMware Virtual GPU"
+       depends on DRM && PCI
+       select FB_DEFERRED_IO
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select DRM_TTM
+       help
+         KMS enabled DRM driver for SVGA2 virtual hardware.
+
+         If unsure say n. The compiled module will be
+         called vmwgfx.ko
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
new file mode 100644 (file)
index 0000000..1a3cb68
--- /dev/null
@@ -0,0 +1,9 @@
+
+ccflags-y := -Iinclude/drm
+
+vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
+           vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
+           vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
+           vmwgfx_overlay.o
+
+obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h
new file mode 100644 (file)
index 0000000..77cb453
--- /dev/null
@@ -0,0 +1,1793 @@
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d_reg.h --
+ *
+ *       SVGA 3D hardware definitions
+ */
+
+#ifndef _SVGA3D_REG_H_
+#define _SVGA3D_REG_H_
+
+#include "svga_reg.h"
+
+
+/*
+ * 3D Hardware Version
+ *
+ *   The hardware version is stored in the SVGA_FIFO_3D_HWVERSION fifo
+ *   register.   Is set by the host and read by the guest.  This lets
+ *   us make new guest drivers which are backwards-compatible with old
+ *   SVGA hardware revisions.  It does not let us support old guest
+ *   drivers.  Good enough for now.
+ *
+ */
+
+#define SVGA3D_MAKE_HWVERSION(major, minor)      (((major) << 16) | ((minor) & 0xFF))
+#define SVGA3D_MAJOR_HWVERSION(version)          ((version) >> 16)
+#define SVGA3D_MINOR_HWVERSION(version)          ((version) & 0xFF)
+
+typedef enum {
+   SVGA3D_HWVERSION_WS5_RC1   = SVGA3D_MAKE_HWVERSION(0, 1),
+   SVGA3D_HWVERSION_WS5_RC2   = SVGA3D_MAKE_HWVERSION(0, 2),
+   SVGA3D_HWVERSION_WS51_RC1  = SVGA3D_MAKE_HWVERSION(0, 3),
+   SVGA3D_HWVERSION_WS6_B1    = SVGA3D_MAKE_HWVERSION(1, 1),
+   SVGA3D_HWVERSION_FUSION_11 = SVGA3D_MAKE_HWVERSION(1, 4),
+   SVGA3D_HWVERSION_WS65_B1   = SVGA3D_MAKE_HWVERSION(2, 0),
+   SVGA3D_HWVERSION_CURRENT   = SVGA3D_HWVERSION_WS65_B1,
+} SVGA3dHardwareVersion;
+
+/*
+ * Generic Types
+ */
+
+typedef uint32 SVGA3dBool; /* 32-bit Bool definition */
+#define SVGA3D_NUM_CLIPPLANES                   6
+#define SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS  8
+
+
+/*
+ * Surface formats.
+ *
+ * If you modify this list, be sure to keep GLUtil.c in sync. It
+ * includes the internal format definition of each surface in
+ * GLUtil_ConvertSurfaceFormat, and it contains a table of
+ * human-readable names in GLUtil_GetFormatName.
+ */
+
+typedef enum SVGA3dSurfaceFormat {
+   SVGA3D_FORMAT_INVALID = 0,
+
+   SVGA3D_X8R8G8B8       = 1,
+   SVGA3D_A8R8G8B8       = 2,
+
+   SVGA3D_R5G6B5         = 3,
+   SVGA3D_X1R5G5B5       = 4,
+   SVGA3D_A1R5G5B5       = 5,
+   SVGA3D_A4R4G4B4       = 6,
+
+   SVGA3D_Z_D32          = 7,
+   SVGA3D_Z_D16          = 8,
+   SVGA3D_Z_D24S8        = 9,
+   SVGA3D_Z_D15S1        = 10,
+
+   SVGA3D_LUMINANCE8            = 11,
+   SVGA3D_LUMINANCE4_ALPHA4     = 12,
+   SVGA3D_LUMINANCE16           = 13,
+   SVGA3D_LUMINANCE8_ALPHA8     = 14,
+
+   SVGA3D_DXT1           = 15,
+   SVGA3D_DXT2           = 16,
+   SVGA3D_DXT3           = 17,
+   SVGA3D_DXT4           = 18,
+   SVGA3D_DXT5           = 19,
+
+   SVGA3D_BUMPU8V8       = 20,
+   SVGA3D_BUMPL6V5U5     = 21,
+   SVGA3D_BUMPX8L8V8U8   = 22,
+   SVGA3D_BUMPL8V8U8     = 23,
+
+   SVGA3D_ARGB_S10E5     = 24,   /* 16-bit floating-point ARGB */
+   SVGA3D_ARGB_S23E8     = 25,   /* 32-bit floating-point ARGB */
+
+   SVGA3D_A2R10G10B10    = 26,
+
+   /* signed formats */
+   SVGA3D_V8U8           = 27,
+   SVGA3D_Q8W8V8U8       = 28,
+   SVGA3D_CxV8U8         = 29,
+
+   /* mixed formats */
+   SVGA3D_X8L8V8U8       = 30,
+   SVGA3D_A2W10V10U10    = 31,
+
+   SVGA3D_ALPHA8         = 32,
+
+   /* Single- and dual-component floating point formats */
+   SVGA3D_R_S10E5        = 33,
+   SVGA3D_R_S23E8        = 34,
+   SVGA3D_RG_S10E5       = 35,
+   SVGA3D_RG_S23E8       = 36,
+
+   /*
+    * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
+    * the most efficient format to use when creating new surfaces
+    * expressly for index or vertex data.
+    */
+   SVGA3D_BUFFER         = 37,
+
+   SVGA3D_Z_D24X8        = 38,
+
+   SVGA3D_V16U16         = 39,
+
+   SVGA3D_G16R16         = 40,
+   SVGA3D_A16B16G16R16   = 41,
+
+   /* Packed Video formats */
+   SVGA3D_UYVY           = 42,
+   SVGA3D_YUY2           = 43,
+
+   SVGA3D_FORMAT_MAX
+} SVGA3dSurfaceFormat;
+
+typedef uint32 SVGA3dColor; /* a, r, g, b */
+
+/*
+ * These match the D3DFORMAT_OP definitions used by Direct3D. We need
+ * them so that we can query the host for what the supported surface
+ * operations are (when we're using the D3D backend, in particular),
+ * and so we can send those operations to the guest.
+ */
+typedef enum {
+   SVGA3DFORMAT_OP_TEXTURE                               = 0x00000001,
+   SVGA3DFORMAT_OP_VOLUMETEXTURE                         = 0x00000002,
+   SVGA3DFORMAT_OP_CUBETEXTURE                           = 0x00000004,
+   SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET                = 0x00000008,
+   SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET              = 0x00000010,
+   SVGA3DFORMAT_OP_ZSTENCIL                              = 0x00000040,
+   SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH   = 0x00000080,
+
+/*
+ * This format can be used as a render target if the current display mode
+ * is the same depth if the alpha channel is ignored. e.g. if the device
+ * can render to A8R8G8B8 when the display mode is X8R8G8B8, then the
+ * format op list entry for A8R8G8B8 should have this cap.
+ */
+   SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET  = 0x00000100,
+
+/*
+ * This format contains DirectDraw support (including Flip).  This flag
+ * should not to be set on alpha formats.
+ */
+   SVGA3DFORMAT_OP_DISPLAYMODE                           = 0x00000400,
+
+/*
+ * The rasterizer can support some level of Direct3D support in this format
+ * and implies that the driver can create a Context in this mode (for some
+ * render target format).  When this flag is set, the SVGA3DFORMAT_OP_DISPLAYMODE
+ * flag must also be set.
+ */
+   SVGA3DFORMAT_OP_3DACCELERATION                        = 0x00000800,
+
+/*
+ * This is set for a private format when the driver has put the bpp in
+ * the structure.
+ */
+   SVGA3DFORMAT_OP_PIXELSIZE                             = 0x00001000,
+
+/*
+ * Indicates that this format can be converted to any RGB format for which
+ * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified
+ */
+   SVGA3DFORMAT_OP_CONVERT_TO_ARGB                       = 0x00002000,
+
+/*
+ * Indicates that this format can be used to create offscreen plain surfaces.
+ */
+   SVGA3DFORMAT_OP_OFFSCREENPLAIN                        = 0x00004000,
+
+/*
+ * Indicated that this format can be read as an SRGB texture (meaning that the
+ * sampler will linearize the looked up data)
+ */
+   SVGA3DFORMAT_OP_SRGBREAD                              = 0x00008000,
+
+/*
+ * Indicates that this format can be used in the bumpmap instructions
+ */
+   SVGA3DFORMAT_OP_BUMPMAP                               = 0x00010000,
+
+/*
+ * Indicates that this format can be sampled by the displacement map sampler
+ */
+   SVGA3DFORMAT_OP_DMAP                                  = 0x00020000,
+
+/*
+ * Indicates that this format cannot be used with texture filtering
+ */
+   SVGA3DFORMAT_OP_NOFILTER                              = 0x00040000,
+
+/*
+ * Indicates that format conversions are supported to this RGB format if
+ * SVGA3DFORMAT_OP_CONVERT_TO_ARGB is specified in the source format.
+ */
+   SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB                    = 0x00080000,
+
+/*
+ * Indicated that this format can be written as an SRGB target (meaning that the
+ * pixel pipe will DE-linearize data on output to format)
+ */
+   SVGA3DFORMAT_OP_SRGBWRITE                             = 0x00100000,
+
+/*
+ * Indicates that this format cannot be used with alpha blending
+ */
+   SVGA3DFORMAT_OP_NOALPHABLEND                          = 0x00200000,
+
+/*
+ * Indicates that the device can auto-generated sublevels for resources
+ * of this format
+ */
+   SVGA3DFORMAT_OP_AUTOGENMIPMAP                         = 0x00400000,
+
+/*
+ * Indicates that this format can be used by vertex texture sampler
+ */
+   SVGA3DFORMAT_OP_VERTEXTEXTURE                         = 0x00800000,
+
+/*
+ * Indicates that this format supports neither texture coordinate wrap
+ * modes, nor mipmapping
+ */
+   SVGA3DFORMAT_OP_NOTEXCOORDWRAPNORMIP                  = 0x01000000
+} SVGA3dFormatOp;
+
+/*
+ * This structure is a conversion of SVGA3DFORMAT_OP_*.
+ * Entries must be located at the same position.
+ */
+typedef union {
+   uint32 value;
+   struct {
+      uint32 texture : 1;
+      uint32 volumeTexture : 1;
+      uint32 cubeTexture : 1;
+      uint32 offscreenRenderTarget : 1;
+      uint32 sameFormatRenderTarget : 1;
+      uint32 unknown1 : 1;
+      uint32 zStencil : 1;
+      uint32 zStencilArbitraryDepth : 1;
+      uint32 sameFormatUpToAlpha : 1;
+      uint32 unknown2 : 1;
+      uint32 displayMode : 1;
+      uint32 acceleration3d : 1;
+      uint32 pixelSize : 1;
+      uint32 convertToARGB : 1;
+      uint32 offscreenPlain : 1;
+      uint32 sRGBRead : 1;
+      uint32 bumpMap : 1;
+      uint32 dmap : 1;
+      uint32 noFilter : 1;
+      uint32 memberOfGroupARGB : 1;
+      uint32 sRGBWrite : 1;
+      uint32 noAlphaBlend : 1;
+      uint32 autoGenMipMap : 1;
+      uint32 vertexTexture : 1;
+      uint32 noTexCoordWrapNorMip : 1;
+   };
+} SVGA3dSurfaceFormatCaps;
+
+/*
+ * SVGA_3D_CMD_SETRENDERSTATE Types.  All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+   SVGA3D_RS_INVALID                   = 0,
+   SVGA3D_RS_ZENABLE                   = 1,     /* SVGA3dBool */
+   SVGA3D_RS_ZWRITEENABLE              = 2,     /* SVGA3dBool */
+   SVGA3D_RS_ALPHATESTENABLE           = 3,     /* SVGA3dBool */
+   SVGA3D_RS_DITHERENABLE              = 4,     /* SVGA3dBool */
+   SVGA3D_RS_BLENDENABLE               = 5,     /* SVGA3dBool */
+   SVGA3D_RS_FOGENABLE                 = 6,     /* SVGA3dBool */
+   SVGA3D_RS_SPECULARENABLE            = 7,     /* SVGA3dBool */
+   SVGA3D_RS_STENCILENABLE             = 8,     /* SVGA3dBool */
+   SVGA3D_RS_LIGHTINGENABLE            = 9,     /* SVGA3dBool */
+   SVGA3D_RS_NORMALIZENORMALS          = 10,    /* SVGA3dBool */
+   SVGA3D_RS_POINTSPRITEENABLE         = 11,    /* SVGA3dBool */
+   SVGA3D_RS_POINTSCALEENABLE          = 12,    /* SVGA3dBool */
+   SVGA3D_RS_STENCILREF                = 13,    /* uint32 */
+   SVGA3D_RS_STENCILMASK               = 14,    /* uint32 */
+   SVGA3D_RS_STENCILWRITEMASK          = 15,    /* uint32 */
+   SVGA3D_RS_FOGSTART                  = 16,    /* float */
+   SVGA3D_RS_FOGEND                    = 17,    /* float */
+   SVGA3D_RS_FOGDENSITY                = 18,    /* float */
+   SVGA3D_RS_POINTSIZE                 = 19,    /* float */
+   SVGA3D_RS_POINTSIZEMIN              = 20,    /* float */
+   SVGA3D_RS_POINTSIZEMAX              = 21,    /* float */
+   SVGA3D_RS_POINTSCALE_A              = 22,    /* float */
+   SVGA3D_RS_POINTSCALE_B              = 23,    /* float */
+   SVGA3D_RS_POINTSCALE_C              = 24,    /* float */
+   SVGA3D_RS_FOGCOLOR                  = 25,    /* SVGA3dColor */
+   SVGA3D_RS_AMBIENT                   = 26,    /* SVGA3dColor */
+   SVGA3D_RS_CLIPPLANEENABLE           = 27,    /* SVGA3dClipPlanes */
+   SVGA3D_RS_FOGMODE                   = 28,    /* SVGA3dFogMode */
+   SVGA3D_RS_FILLMODE                  = 29,    /* SVGA3dFillMode */
+   SVGA3D_RS_SHADEMODE                 = 30,    /* SVGA3dShadeMode */
+   SVGA3D_RS_LINEPATTERN               = 31,    /* SVGA3dLinePattern */
+   SVGA3D_RS_SRCBLEND                  = 32,    /* SVGA3dBlendOp */
+   SVGA3D_RS_DSTBLEND                  = 33,    /* SVGA3dBlendOp */
+   SVGA3D_RS_BLENDEQUATION             = 34,    /* SVGA3dBlendEquation */
+   SVGA3D_RS_CULLMODE                  = 35,    /* SVGA3dFace */
+   SVGA3D_RS_ZFUNC                     = 36,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_ALPHAFUNC                 = 37,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_STENCILFUNC               = 38,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_STENCILFAIL               = 39,    /* SVGA3dStencilOp */
+   SVGA3D_RS_STENCILZFAIL              = 40,    /* SVGA3dStencilOp */
+   SVGA3D_RS_STENCILPASS               = 41,    /* SVGA3dStencilOp */
+   SVGA3D_RS_ALPHAREF                  = 42,    /* float (0.0 .. 1.0) */
+   SVGA3D_RS_FRONTWINDING              = 43,    /* SVGA3dFrontWinding */
+   SVGA3D_RS_COORDINATETYPE            = 44,    /* SVGA3dCoordinateType */
+   SVGA3D_RS_ZBIAS                     = 45,    /* float */
+   SVGA3D_RS_RANGEFOGENABLE            = 46,    /* SVGA3dBool */
+   SVGA3D_RS_COLORWRITEENABLE          = 47,    /* SVGA3dColorMask */
+   SVGA3D_RS_VERTEXMATERIALENABLE      = 48,    /* SVGA3dBool */
+   SVGA3D_RS_DIFFUSEMATERIALSOURCE     = 49,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_SPECULARMATERIALSOURCE    = 50,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_AMBIENTMATERIALSOURCE     = 51,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_EMISSIVEMATERIALSOURCE    = 52,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_TEXTUREFACTOR             = 53,    /* SVGA3dColor */
+   SVGA3D_RS_LOCALVIEWER               = 54,    /* SVGA3dBool */
+   SVGA3D_RS_SCISSORTESTENABLE         = 55,    /* SVGA3dBool */
+   SVGA3D_RS_BLENDCOLOR                = 56,    /* SVGA3dColor */
+   SVGA3D_RS_STENCILENABLE2SIDED       = 57,    /* SVGA3dBool */
+   SVGA3D_RS_CCWSTENCILFUNC            = 58,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_CCWSTENCILFAIL            = 59,    /* SVGA3dStencilOp */
+   SVGA3D_RS_CCWSTENCILZFAIL           = 60,    /* SVGA3dStencilOp */
+   SVGA3D_RS_CCWSTENCILPASS            = 61,    /* SVGA3dStencilOp */
+   SVGA3D_RS_VERTEXBLEND               = 62,    /* SVGA3dVertexBlendFlags */
+   SVGA3D_RS_SLOPESCALEDEPTHBIAS       = 63,    /* float */
+   SVGA3D_RS_DEPTHBIAS                 = 64,    /* float */
+
+
+   /*
+    * Output Gamma Level
+    *
+    * Output gamma effects the gamma curve of colors that are output from the
+    * rendering pipeline.  A value of 1.0 specifies a linear color space. If the
+    * value is <= 0.0, gamma correction is ignored and linear color space is
+    * used.
+    */
+
+   SVGA3D_RS_OUTPUTGAMMA               = 65,    /* float */
+   SVGA3D_RS_ZVISIBLE                  = 66,    /* SVGA3dBool */
+   SVGA3D_RS_LASTPIXEL                 = 67,    /* SVGA3dBool */
+   SVGA3D_RS_CLIPPING                  = 68,    /* SVGA3dBool */
+   SVGA3D_RS_WRAP0                     = 69,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP1                     = 70,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP2                     = 71,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP3                     = 72,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP4                     = 73,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP5                     = 74,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP6                     = 75,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP7                     = 76,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP8                     = 77,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP9                     = 78,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP10                    = 79,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP11                    = 80,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP12                    = 81,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP13                    = 82,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP14                    = 83,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP15                    = 84,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_MULTISAMPLEANTIALIAS      = 85,    /* SVGA3dBool */
+   SVGA3D_RS_MULTISAMPLEMASK           = 86,    /* uint32 */
+   SVGA3D_RS_INDEXEDVERTEXBLENDENABLE  = 87,    /* SVGA3dBool */
+   SVGA3D_RS_TWEENFACTOR               = 88,    /* float */
+   SVGA3D_RS_ANTIALIASEDLINEENABLE     = 89,    /* SVGA3dBool */
+   SVGA3D_RS_COLORWRITEENABLE1         = 90,    /* SVGA3dColorMask */
+   SVGA3D_RS_COLORWRITEENABLE2         = 91,    /* SVGA3dColorMask */
+   SVGA3D_RS_COLORWRITEENABLE3         = 92,    /* SVGA3dColorMask */
+   SVGA3D_RS_SEPARATEALPHABLENDENABLE  = 93,    /* SVGA3dBool */
+   SVGA3D_RS_SRCBLENDALPHA             = 94,    /* SVGA3dBlendOp */
+   SVGA3D_RS_DSTBLENDALPHA             = 95,    /* SVGA3dBlendOp */
+   SVGA3D_RS_BLENDEQUATIONALPHA        = 96,    /* SVGA3dBlendEquation */
+   SVGA3D_RS_MAX
+} SVGA3dRenderStateName;
+
+typedef enum {
+   SVGA3D_VERTEXMATERIAL_NONE     = 0,    /* Use the value in the current material */
+   SVGA3D_VERTEXMATERIAL_DIFFUSE  = 1,    /* Use the value in the diffuse component */
+   SVGA3D_VERTEXMATERIAL_SPECULAR = 2,    /* Use the value in the specular component */
+} SVGA3dVertexMaterial;
+
+typedef enum {
+   SVGA3D_FILLMODE_INVALID = 0,
+   SVGA3D_FILLMODE_POINT   = 1,
+   SVGA3D_FILLMODE_LINE    = 2,
+   SVGA3D_FILLMODE_FILL    = 3,
+   SVGA3D_FILLMODE_MAX
+} SVGA3dFillModeType;
+
+
+typedef
+union {
+   struct {
+      uint16   mode;       /* SVGA3dFillModeType */
+      uint16   face;       /* SVGA3dFace */
+   };
+   uint32 uintValue;
+} SVGA3dFillMode;
+
+typedef enum {
+   SVGA3D_SHADEMODE_INVALID = 0,
+   SVGA3D_SHADEMODE_FLAT    = 1,
+   SVGA3D_SHADEMODE_SMOOTH  = 2,
+   SVGA3D_SHADEMODE_PHONG   = 3,     /* Not supported */
+   SVGA3D_SHADEMODE_MAX
+} SVGA3dShadeMode;
+
+typedef
+union {
+   struct {
+      uint16 repeat;
+      uint16 pattern;
+   };
+   uint32 uintValue;
+} SVGA3dLinePattern;
+
+typedef enum {
+   SVGA3D_BLENDOP_INVALID            = 0,
+   SVGA3D_BLENDOP_ZERO               = 1,
+   SVGA3D_BLENDOP_ONE                = 2,
+   SVGA3D_BLENDOP_SRCCOLOR           = 3,
+   SVGA3D_BLENDOP_INVSRCCOLOR        = 4,
+   SVGA3D_BLENDOP_SRCALPHA           = 5,
+   SVGA3D_BLENDOP_INVSRCALPHA        = 6,
+   SVGA3D_BLENDOP_DESTALPHA          = 7,
+   SVGA3D_BLENDOP_INVDESTALPHA       = 8,
+   SVGA3D_BLENDOP_DESTCOLOR          = 9,
+   SVGA3D_BLENDOP_INVDESTCOLOR       = 10,
+   SVGA3D_BLENDOP_SRCALPHASAT        = 11,
+   SVGA3D_BLENDOP_BLENDFACTOR        = 12,
+   SVGA3D_BLENDOP_INVBLENDFACTOR     = 13,
+   SVGA3D_BLENDOP_MAX
+} SVGA3dBlendOp;
+
+typedef enum {
+   SVGA3D_BLENDEQ_INVALID            = 0,
+   SVGA3D_BLENDEQ_ADD                = 1,
+   SVGA3D_BLENDEQ_SUBTRACT           = 2,
+   SVGA3D_BLENDEQ_REVSUBTRACT        = 3,
+   SVGA3D_BLENDEQ_MINIMUM            = 4,
+   SVGA3D_BLENDEQ_MAXIMUM            = 5,
+   SVGA3D_BLENDEQ_MAX
+} SVGA3dBlendEquation;
+
+typedef enum {
+   SVGA3D_FRONTWINDING_INVALID = 0,
+   SVGA3D_FRONTWINDING_CW      = 1,
+   SVGA3D_FRONTWINDING_CCW     = 2,
+   SVGA3D_FRONTWINDING_MAX
+} SVGA3dFrontWinding;
+
+typedef enum {
+   SVGA3D_FACE_INVALID  = 0,
+   SVGA3D_FACE_NONE     = 1,
+   SVGA3D_FACE_FRONT    = 2,
+   SVGA3D_FACE_BACK     = 3,
+   SVGA3D_FACE_FRONT_BACK = 4,
+   SVGA3D_FACE_MAX
+} SVGA3dFace;
+
+/*
+ * The order and the values should not be changed
+ */
+
+typedef enum {
+   SVGA3D_CMP_INVALID              = 0,
+   SVGA3D_CMP_NEVER                = 1,
+   SVGA3D_CMP_LESS                 = 2,
+   SVGA3D_CMP_EQUAL                = 3,
+   SVGA3D_CMP_LESSEQUAL            = 4,
+   SVGA3D_CMP_GREATER              = 5,
+   SVGA3D_CMP_NOTEQUAL             = 6,
+   SVGA3D_CMP_GREATEREQUAL         = 7,
+   SVGA3D_CMP_ALWAYS               = 8,
+   SVGA3D_CMP_MAX
+} SVGA3dCmpFunc;
+
+/*
+ * SVGA3D_FOGFUNC_* specifies the fog equation, or PER_VERTEX which allows
+ * the fog factor to be specified in the alpha component of the specular
+ * (a.k.a. secondary) vertex color.
+ */
+typedef enum {
+   SVGA3D_FOGFUNC_INVALID          = 0,
+   SVGA3D_FOGFUNC_EXP              = 1,
+   SVGA3D_FOGFUNC_EXP2             = 2,
+   SVGA3D_FOGFUNC_LINEAR           = 3,
+   SVGA3D_FOGFUNC_PER_VERTEX       = 4
+} SVGA3dFogFunction;
+
+/*
+ * SVGA3D_FOGTYPE_* specifies if fog factors are computed on a per-vertex
+ * or per-pixel basis.
+ */
+typedef enum {
+   SVGA3D_FOGTYPE_INVALID          = 0,
+   SVGA3D_FOGTYPE_VERTEX           = 1,
+   SVGA3D_FOGTYPE_PIXEL            = 2,
+   SVGA3D_FOGTYPE_MAX              = 3
+} SVGA3dFogType;
+
+/*
+ * SVGA3D_FOGBASE_* selects depth or range-based fog. Depth-based fog is
+ * computed using the eye Z value of each pixel (or vertex), whereas range-
+ * based fog is computed using the actual distance (range) to the eye.
+ */
+typedef enum {
+   SVGA3D_FOGBASE_INVALID          = 0,
+   SVGA3D_FOGBASE_DEPTHBASED       = 1,
+   SVGA3D_FOGBASE_RANGEBASED       = 2,
+   SVGA3D_FOGBASE_MAX              = 3
+} SVGA3dFogBase;
+
+typedef enum {
+   SVGA3D_STENCILOP_INVALID        = 0,
+   SVGA3D_STENCILOP_KEEP           = 1,
+   SVGA3D_STENCILOP_ZERO           = 2,
+   SVGA3D_STENCILOP_REPLACE        = 3,
+   SVGA3D_STENCILOP_INCRSAT        = 4,
+   SVGA3D_STENCILOP_DECRSAT        = 5,
+   SVGA3D_STENCILOP_INVERT         = 6,
+   SVGA3D_STENCILOP_INCR           = 7,
+   SVGA3D_STENCILOP_DECR           = 8,
+   SVGA3D_STENCILOP_MAX
+} SVGA3dStencilOp;
+
+typedef enum {
+   SVGA3D_CLIPPLANE_0              = (1 << 0),
+   SVGA3D_CLIPPLANE_1              = (1 << 1),
+   SVGA3D_CLIPPLANE_2              = (1 << 2),
+   SVGA3D_CLIPPLANE_3              = (1 << 3),
+   SVGA3D_CLIPPLANE_4              = (1 << 4),
+   SVGA3D_CLIPPLANE_5              = (1 << 5),
+} SVGA3dClipPlanes;
+
+typedef enum {
+   SVGA3D_CLEAR_COLOR              = 0x1,
+   SVGA3D_CLEAR_DEPTH              = 0x2,
+   SVGA3D_CLEAR_STENCIL            = 0x4
+} SVGA3dClearFlag;
+
+typedef enum {
+   SVGA3D_RT_DEPTH                 = 0,
+   SVGA3D_RT_STENCIL               = 1,
+   SVGA3D_RT_COLOR0                = 2,
+   SVGA3D_RT_COLOR1                = 3,
+   SVGA3D_RT_COLOR2                = 4,
+   SVGA3D_RT_COLOR3                = 5,
+   SVGA3D_RT_COLOR4                = 6,
+   SVGA3D_RT_COLOR5                = 7,
+   SVGA3D_RT_COLOR6                = 8,
+   SVGA3D_RT_COLOR7                = 9,
+   SVGA3D_RT_MAX,
+   SVGA3D_RT_INVALID               = ((uint32)-1),
+} SVGA3dRenderTargetType;
+
+#define SVGA3D_MAX_RT_COLOR (SVGA3D_RT_COLOR7 - SVGA3D_RT_COLOR0 + 1)
+
+typedef
+union {
+   struct {
+      uint32  red   : 1;
+      uint32  green : 1;
+      uint32  blue  : 1;
+      uint32  alpha : 1;
+   };
+   uint32 uintValue;
+} SVGA3dColorMask;
+
+typedef enum {
+   SVGA3D_VBLEND_DISABLE            = 0,
+   SVGA3D_VBLEND_1WEIGHT            = 1,
+   SVGA3D_VBLEND_2WEIGHT            = 2,
+   SVGA3D_VBLEND_3WEIGHT            = 3,
+} SVGA3dVertexBlendFlags;
+
+typedef enum {
+   SVGA3D_WRAPCOORD_0   = 1 << 0,
+   SVGA3D_WRAPCOORD_1   = 1 << 1,
+   SVGA3D_WRAPCOORD_2   = 1 << 2,
+   SVGA3D_WRAPCOORD_3   = 1 << 3,
+   SVGA3D_WRAPCOORD_ALL = 0xF,
+} SVGA3dWrapFlags;
+
+/*
+ * SVGA_3D_CMD_TEXTURESTATE Types.  All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+   SVGA3D_TS_INVALID                    = 0,
+   SVGA3D_TS_BIND_TEXTURE               = 1,    /* SVGA3dSurfaceId */
+   SVGA3D_TS_COLOROP                    = 2,    /* SVGA3dTextureCombiner */
+   SVGA3D_TS_COLORARG1                  = 3,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_COLORARG2                  = 4,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAOP                    = 5,    /* SVGA3dTextureCombiner */
+   SVGA3D_TS_ALPHAARG1                  = 6,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAARG2                  = 7,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ADDRESSU                   = 8,    /* SVGA3dTextureAddress */
+   SVGA3D_TS_ADDRESSV                   = 9,    /* SVGA3dTextureAddress */
+   SVGA3D_TS_MIPFILTER                  = 10,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_MAGFILTER                  = 11,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_MINFILTER                  = 12,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_BORDERCOLOR                = 13,   /* SVGA3dColor */
+   SVGA3D_TS_TEXCOORDINDEX              = 14,   /* uint32 */
+   SVGA3D_TS_TEXTURETRANSFORMFLAGS      = 15,   /* SVGA3dTexTransformFlags */
+   SVGA3D_TS_TEXCOORDGEN                = 16,   /* SVGA3dTextureCoordGen */
+   SVGA3D_TS_BUMPENVMAT00               = 17,   /* float */
+   SVGA3D_TS_BUMPENVMAT01               = 18,   /* float */
+   SVGA3D_TS_BUMPENVMAT10               = 19,   /* float */
+   SVGA3D_TS_BUMPENVMAT11               = 20,   /* float */
+   SVGA3D_TS_TEXTURE_MIPMAP_LEVEL       = 21,   /* uint32 */
+   SVGA3D_TS_TEXTURE_LOD_BIAS           = 22,   /* float */
+   SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL  = 23,   /* uint32 */
+   SVGA3D_TS_ADDRESSW                   = 24,   /* SVGA3dTextureAddress */
+
+
+   /*
+    * Sampler Gamma Level
+    *
+    * Sampler gamma effects the color of samples taken from the sampler.  A
+    * value of 1.0 will produce linear samples.  If the value is <= 0.0 the
+    * gamma value is ignored and a linear space is used.
+    */
+
+   SVGA3D_TS_GAMMA                      = 25,   /* float */
+   SVGA3D_TS_BUMPENVLSCALE              = 26,   /* float */
+   SVGA3D_TS_BUMPENVLOFFSET             = 27,   /* float */
+   SVGA3D_TS_COLORARG0                  = 28,   /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAARG0                  = 29,   /* SVGA3dTextureArgData */
+   SVGA3D_TS_MAX
+} SVGA3dTextureStateName;
+
+typedef enum {
+   SVGA3D_TC_INVALID                   = 0,
+   SVGA3D_TC_DISABLE                   = 1,
+   SVGA3D_TC_SELECTARG1                = 2,
+   SVGA3D_TC_SELECTARG2                = 3,
+   SVGA3D_TC_MODULATE                  = 4,
+   SVGA3D_TC_ADD                       = 5,
+   SVGA3D_TC_ADDSIGNED                 = 6,
+   SVGA3D_TC_SUBTRACT                  = 7,
+   SVGA3D_TC_BLENDTEXTUREALPHA         = 8,
+   SVGA3D_TC_BLENDDIFFUSEALPHA         = 9,
+   SVGA3D_TC_BLENDCURRENTALPHA         = 10,
+   SVGA3D_TC_BLENDFACTORALPHA          = 11,
+   SVGA3D_TC_MODULATE2X                = 12,
+   SVGA3D_TC_MODULATE4X                = 13,
+   SVGA3D_TC_DSDT                      = 14,
+   SVGA3D_TC_DOTPRODUCT3               = 15,
+   SVGA3D_TC_BLENDTEXTUREALPHAPM       = 16,
+   SVGA3D_TC_ADDSIGNED2X               = 17,
+   SVGA3D_TC_ADDSMOOTH                 = 18,
+   SVGA3D_TC_PREMODULATE               = 19,
+   SVGA3D_TC_MODULATEALPHA_ADDCOLOR    = 20,
+   SVGA3D_TC_MODULATECOLOR_ADDALPHA    = 21,
+   SVGA3D_TC_MODULATEINVALPHA_ADDCOLOR = 22,
+   SVGA3D_TC_MODULATEINVCOLOR_ADDALPHA = 23,
+   SVGA3D_TC_BUMPENVMAPLUMINANCE       = 24,
+   SVGA3D_TC_MULTIPLYADD               = 25,
+   SVGA3D_TC_LERP                      = 26,
+   SVGA3D_TC_MAX
+} SVGA3dTextureCombiner;
+
+#define SVGA3D_TC_CAP_BIT(svga3d_tc_op) (svga3d_tc_op ? (1 << (svga3d_tc_op - 1)) : 0)
+
+typedef enum {
+   SVGA3D_TEX_ADDRESS_INVALID    = 0,
+   SVGA3D_TEX_ADDRESS_WRAP       = 1,
+   SVGA3D_TEX_ADDRESS_MIRROR     = 2,
+   SVGA3D_TEX_ADDRESS_CLAMP      = 3,
+   SVGA3D_TEX_ADDRESS_BORDER     = 4,
+   SVGA3D_TEX_ADDRESS_MIRRORONCE = 5,
+   SVGA3D_TEX_ADDRESS_EDGE       = 6,
+   SVGA3D_TEX_ADDRESS_MAX
+} SVGA3dTextureAddress;
+
+/*
+ * SVGA3D_TEX_FILTER_NONE as the minification filter means mipmapping is
+ * disabled, and the rasterizer should use the magnification filter instead.
+ */
+typedef enum {
+   SVGA3D_TEX_FILTER_NONE           = 0,
+   SVGA3D_TEX_FILTER_NEAREST        = 1,
+   SVGA3D_TEX_FILTER_LINEAR         = 2,
+   SVGA3D_TEX_FILTER_ANISOTROPIC    = 3,
+   SVGA3D_TEX_FILTER_FLATCUBIC      = 4, // Deprecated, not implemented
+   SVGA3D_TEX_FILTER_GAUSSIANCUBIC  = 5, // Deprecated, not implemented
+   SVGA3D_TEX_FILTER_PYRAMIDALQUAD  = 6, // Not currently implemented
+   SVGA3D_TEX_FILTER_GAUSSIANQUAD   = 7, // Not currently implemented
+   SVGA3D_TEX_FILTER_MAX
+} SVGA3dTextureFilter;
+
+typedef enum {
+   SVGA3D_TEX_TRANSFORM_OFF    = 0,
+   SVGA3D_TEX_TRANSFORM_S      = (1 << 0),
+   SVGA3D_TEX_TRANSFORM_T      = (1 << 1),
+   SVGA3D_TEX_TRANSFORM_R      = (1 << 2),
+   SVGA3D_TEX_TRANSFORM_Q      = (1 << 3),
+   SVGA3D_TEX_PROJECTED        = (1 << 15),
+} SVGA3dTexTransformFlags;
+
+typedef enum {
+   SVGA3D_TEXCOORD_GEN_OFF              = 0,
+   SVGA3D_TEXCOORD_GEN_EYE_POSITION     = 1,
+   SVGA3D_TEXCOORD_GEN_EYE_NORMAL       = 2,
+   SVGA3D_TEXCOORD_GEN_REFLECTIONVECTOR = 3,
+   SVGA3D_TEXCOORD_GEN_SPHERE           = 4,
+   SVGA3D_TEXCOORD_GEN_MAX
+} SVGA3dTextureCoordGen;
+
+/*
+ * Texture argument constants for texture combiner
+ */
+typedef enum {
+   SVGA3D_TA_INVALID    = 0,
+   SVGA3D_TA_CONSTANT   = 1,
+   SVGA3D_TA_PREVIOUS   = 2,
+   SVGA3D_TA_DIFFUSE    = 3,
+   SVGA3D_TA_TEXTURE    = 4,
+   SVGA3D_TA_SPECULAR   = 5,
+   SVGA3D_TA_MAX
+} SVGA3dTextureArgData;
+
+#define SVGA3D_TM_MASK_LEN 4
+
+/* Modifiers for texture argument constants defined above. */
+typedef enum {
+   SVGA3D_TM_NONE       = 0,
+   SVGA3D_TM_ALPHA      = (1 << SVGA3D_TM_MASK_LEN),
+   SVGA3D_TM_ONE_MINUS  = (2 << SVGA3D_TM_MASK_LEN),
+} SVGA3dTextureArgModifier;
+
+#define SVGA3D_INVALID_ID         ((uint32)-1)
+#define SVGA3D_MAX_CLIP_PLANES    6
+
+/*
+ * This is the limit to the number of fixed-function texture
+ * transforms and texture coordinates we can support. It does *not*
+ * correspond to the number of texture image units (samplers) we
+ * support!
+ */
+#define SVGA3D_MAX_TEXTURE_COORDS 8
+
+/*
+ * Vertex declarations
+ *
+ * Notes:
+ *
+ * SVGA3D_DECLUSAGE_POSITIONT is for pre-transformed vertices. If you
+ * draw with any POSITIONT vertex arrays, the programmable vertex
+ * pipeline will be implicitly disabled. Drawing will take place as if
+ * no vertex shader was bound.
+ */
+
+typedef enum {
+   SVGA3D_DECLUSAGE_POSITION     = 0,
+   SVGA3D_DECLUSAGE_BLENDWEIGHT,       //  1
+   SVGA3D_DECLUSAGE_BLENDINDICES,      //  2
+   SVGA3D_DECLUSAGE_NORMAL,            //  3
+   SVGA3D_DECLUSAGE_PSIZE,             //  4
+   SVGA3D_DECLUSAGE_TEXCOORD,          //  5
+   SVGA3D_DECLUSAGE_TANGENT,           //  6
+   SVGA3D_DECLUSAGE_BINORMAL,          //  7
+   SVGA3D_DECLUSAGE_TESSFACTOR,        //  8
+   SVGA3D_DECLUSAGE_POSITIONT,         //  9
+   SVGA3D_DECLUSAGE_COLOR,             // 10
+   SVGA3D_DECLUSAGE_FOG,               // 11
+   SVGA3D_DECLUSAGE_DEPTH,             // 12
+   SVGA3D_DECLUSAGE_SAMPLE,            // 13
+   SVGA3D_DECLUSAGE_MAX
+} SVGA3dDeclUsage;
+
+typedef enum {
+   SVGA3D_DECLMETHOD_DEFAULT     = 0,
+   SVGA3D_DECLMETHOD_PARTIALU,
+   SVGA3D_DECLMETHOD_PARTIALV,
+   SVGA3D_DECLMETHOD_CROSSUV,          // Normal
+   SVGA3D_DECLMETHOD_UV,
+   SVGA3D_DECLMETHOD_LOOKUP,           // Lookup a displacement map
+   SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map
+} SVGA3dDeclMethod;
+
+typedef enum {
+   SVGA3D_DECLTYPE_FLOAT1        =  0,
+   SVGA3D_DECLTYPE_FLOAT2        =  1,
+   SVGA3D_DECLTYPE_FLOAT3        =  2,
+   SVGA3D_DECLTYPE_FLOAT4        =  3,
+   SVGA3D_DECLTYPE_D3DCOLOR      =  4,
+   SVGA3D_DECLTYPE_UBYTE4        =  5,
+   SVGA3D_DECLTYPE_SHORT2        =  6,
+   SVGA3D_DECLTYPE_SHORT4        =  7,
+   SVGA3D_DECLTYPE_UBYTE4N       =  8,
+   SVGA3D_DECLTYPE_SHORT2N       =  9,
+   SVGA3D_DECLTYPE_SHORT4N       = 10,
+   SVGA3D_DECLTYPE_USHORT2N      = 11,
+   SVGA3D_DECLTYPE_USHORT4N      = 12,
+   SVGA3D_DECLTYPE_UDEC3         = 13,
+   SVGA3D_DECLTYPE_DEC3N         = 14,
+   SVGA3D_DECLTYPE_FLOAT16_2     = 15,
+   SVGA3D_DECLTYPE_FLOAT16_4     = 16,
+   SVGA3D_DECLTYPE_MAX,
+} SVGA3dDeclType;
+
+/*
+ * This structure is used for the divisor for geometry instancing;
+ * it's a direct translation of the Direct3D equivalent.
+ */
+typedef union {
+   struct {
+      /*
+       * For index data, this number represents the number of instances to draw.
+       * For instance data, this number represents the number of
+       * instances/vertex in this stream
+       */
+      uint32 count : 30;
+
+      /*
+       * This is 1 if this is supposed to be the data that is repeated for
+       * every instance.
+       */
+      uint32 indexedData : 1;
+
+      /*
+       * This is 1 if this is supposed to be the per-instance data.
+       */
+      uint32 instanceData : 1;
+   };
+
+   uint32 value;
+} SVGA3dVertexDivisor;
+
+typedef enum {
+   SVGA3D_PRIMITIVE_INVALID                     = 0,
+   SVGA3D_PRIMITIVE_TRIANGLELIST                = 1,
+   SVGA3D_PRIMITIVE_POINTLIST                   = 2,
+   SVGA3D_PRIMITIVE_LINELIST                    = 3,
+   SVGA3D_PRIMITIVE_LINESTRIP                   = 4,
+   SVGA3D_PRIMITIVE_TRIANGLESTRIP               = 5,
+   SVGA3D_PRIMITIVE_TRIANGLEFAN                 = 6,
+   SVGA3D_PRIMITIVE_MAX
+} SVGA3dPrimitiveType;
+
+typedef enum {
+   SVGA3D_COORDINATE_INVALID                   = 0,
+   SVGA3D_COORDINATE_LEFTHANDED                = 1,
+   SVGA3D_COORDINATE_RIGHTHANDED               = 2,
+   SVGA3D_COORDINATE_MAX
+} SVGA3dCoordinateType;
+
+typedef enum {
+   SVGA3D_TRANSFORM_INVALID                     = 0,
+   SVGA3D_TRANSFORM_WORLD                       = 1,
+   SVGA3D_TRANSFORM_VIEW                        = 2,
+   SVGA3D_TRANSFORM_PROJECTION                  = 3,
+   SVGA3D_TRANSFORM_TEXTURE0                    = 4,
+   SVGA3D_TRANSFORM_TEXTURE1                    = 5,
+   SVGA3D_TRANSFORM_TEXTURE2                    = 6,
+   SVGA3D_TRANSFORM_TEXTURE3                    = 7,
+   SVGA3D_TRANSFORM_TEXTURE4                    = 8,
+   SVGA3D_TRANSFORM_TEXTURE5                    = 9,
+   SVGA3D_TRANSFORM_TEXTURE6                    = 10,
+   SVGA3D_TRANSFORM_TEXTURE7                    = 11,
+   SVGA3D_TRANSFORM_WORLD1                      = 12,
+   SVGA3D_TRANSFORM_WORLD2                      = 13,
+   SVGA3D_TRANSFORM_WORLD3                      = 14,
+   SVGA3D_TRANSFORM_MAX
+} SVGA3dTransformType;
+
+typedef enum {
+   SVGA3D_LIGHTTYPE_INVALID                     = 0,
+   SVGA3D_LIGHTTYPE_POINT                       = 1,
+   SVGA3D_LIGHTTYPE_SPOT1                       = 2, /* 1-cone, in degrees */
+   SVGA3D_LIGHTTYPE_SPOT2                       = 3, /* 2-cone, in radians */
+   SVGA3D_LIGHTTYPE_DIRECTIONAL                 = 4,
+   SVGA3D_LIGHTTYPE_MAX
+} SVGA3dLightType;
+
+typedef enum {
+   SVGA3D_CUBEFACE_POSX                         = 0,
+   SVGA3D_CUBEFACE_NEGX                         = 1,
+   SVGA3D_CUBEFACE_POSY                         = 2,
+   SVGA3D_CUBEFACE_NEGY                         = 3,
+   SVGA3D_CUBEFACE_POSZ                         = 4,
+   SVGA3D_CUBEFACE_NEGZ                         = 5,
+} SVGA3dCubeFace;
+
+typedef enum {
+   SVGA3D_SHADERTYPE_COMPILED_DX8               = 0,
+   SVGA3D_SHADERTYPE_VS                         = 1,
+   SVGA3D_SHADERTYPE_PS                         = 2,
+   SVGA3D_SHADERTYPE_MAX
+} SVGA3dShaderType;
+
+typedef enum {
+   SVGA3D_CONST_TYPE_FLOAT                      = 0,
+   SVGA3D_CONST_TYPE_INT                        = 1,
+   SVGA3D_CONST_TYPE_BOOL                       = 2,
+} SVGA3dShaderConstType;
+
+#define SVGA3D_MAX_SURFACE_FACES                6
+
+typedef enum {
+   SVGA3D_STRETCH_BLT_POINT                     = 0,
+   SVGA3D_STRETCH_BLT_LINEAR                    = 1,
+   SVGA3D_STRETCH_BLT_MAX
+} SVGA3dStretchBltMode;
+
+typedef enum {
+   SVGA3D_QUERYTYPE_OCCLUSION                   = 0,
+   SVGA3D_QUERYTYPE_MAX
+} SVGA3dQueryType;
+
+typedef enum {
+   SVGA3D_QUERYSTATE_PENDING     = 0,      /* Waiting on the host (set by guest) */
+   SVGA3D_QUERYSTATE_SUCCEEDED   = 1,      /* Completed successfully (set by host) */
+   SVGA3D_QUERYSTATE_FAILED      = 2,      /* Completed unsuccessfully (set by host) */
+   SVGA3D_QUERYSTATE_NEW         = 3,      /* Never submitted (For guest use only) */
+} SVGA3dQueryState;
+
+typedef enum {
+   SVGA3D_WRITE_HOST_VRAM        = 1,
+   SVGA3D_READ_HOST_VRAM         = 2,
+} SVGA3dTransferType;
+
+/*
+ * The maximum number vertex arrays we're guaranteed to support in
+ * SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_VERTEX_ARRAYS   32
+
+/*
+ * Identifiers for commands in the command FIFO.
+ *
+ * IDs between 1000 and 1039 (inclusive) were used by obsolete versions of
+ * the SVGA3D protocol and remain reserved; they should not be used in the
+ * future.
+ *
+ * IDs between 1040 and 1999 (inclusive) are available for use by the
+ * current SVGA3D protocol.
+ *
+ * FIFO clients other than SVGA3D should stay below 1000, or at 2000
+ * and up.
+ */
+
+#define SVGA_3D_CMD_LEGACY_BASE            1000
+#define SVGA_3D_CMD_BASE                   1040
+
+#define SVGA_3D_CMD_SURFACE_DEFINE         SVGA_3D_CMD_BASE + 0
+#define SVGA_3D_CMD_SURFACE_DESTROY        SVGA_3D_CMD_BASE + 1
+#define SVGA_3D_CMD_SURFACE_COPY           SVGA_3D_CMD_BASE + 2
+#define SVGA_3D_CMD_SURFACE_STRETCHBLT     SVGA_3D_CMD_BASE + 3
+#define SVGA_3D_CMD_SURFACE_DMA            SVGA_3D_CMD_BASE + 4
+#define SVGA_3D_CMD_CONTEXT_DEFINE         SVGA_3D_CMD_BASE + 5
+#define SVGA_3D_CMD_CONTEXT_DESTROY        SVGA_3D_CMD_BASE + 6
+#define SVGA_3D_CMD_SETTRANSFORM           SVGA_3D_CMD_BASE + 7
+#define SVGA_3D_CMD_SETZRANGE              SVGA_3D_CMD_BASE + 8
+#define SVGA_3D_CMD_SETRENDERSTATE         SVGA_3D_CMD_BASE + 9
+#define SVGA_3D_CMD_SETRENDERTARGET        SVGA_3D_CMD_BASE + 10
+#define SVGA_3D_CMD_SETTEXTURESTATE        SVGA_3D_CMD_BASE + 11
+#define SVGA_3D_CMD_SETMATERIAL            SVGA_3D_CMD_BASE + 12
+#define SVGA_3D_CMD_SETLIGHTDATA           SVGA_3D_CMD_BASE + 13
+#define SVGA_3D_CMD_SETLIGHTENABLED        SVGA_3D_CMD_BASE + 14
+#define SVGA_3D_CMD_SETVIEWPORT            SVGA_3D_CMD_BASE + 15
+#define SVGA_3D_CMD_SETCLIPPLANE           SVGA_3D_CMD_BASE + 16
+#define SVGA_3D_CMD_CLEAR                  SVGA_3D_CMD_BASE + 17
+#define SVGA_3D_CMD_PRESENT                SVGA_3D_CMD_BASE + 18    // Deprecated
+#define SVGA_3D_CMD_SHADER_DEFINE          SVGA_3D_CMD_BASE + 19
+#define SVGA_3D_CMD_SHADER_DESTROY         SVGA_3D_CMD_BASE + 20
+#define SVGA_3D_CMD_SET_SHADER             SVGA_3D_CMD_BASE + 21
+#define SVGA_3D_CMD_SET_SHADER_CONST       SVGA_3D_CMD_BASE + 22
+#define SVGA_3D_CMD_DRAW_PRIMITIVES        SVGA_3D_CMD_BASE + 23
+#define SVGA_3D_CMD_SETSCISSORRECT         SVGA_3D_CMD_BASE + 24
+#define SVGA_3D_CMD_BEGIN_QUERY            SVGA_3D_CMD_BASE + 25
+#define SVGA_3D_CMD_END_QUERY              SVGA_3D_CMD_BASE + 26
+#define SVGA_3D_CMD_WAIT_FOR_QUERY         SVGA_3D_CMD_BASE + 27
+#define SVGA_3D_CMD_PRESENT_READBACK       SVGA_3D_CMD_BASE + 28    // Deprecated
+#define SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN SVGA_3D_CMD_BASE + 29
+#define SVGA_3D_CMD_MAX                    SVGA_3D_CMD_BASE + 30
+
+#define SVGA_3D_CMD_FUTURE_MAX             2000
+
+/*
+ * Common substructures used in multiple FIFO commands:
+ */
+
+typedef struct {
+   union {
+      struct {
+         uint16  function;       // SVGA3dFogFunction
+         uint8   type;           // SVGA3dFogType
+         uint8   base;           // SVGA3dFogBase
+      };
+      uint32     uintValue;
+   };
+} SVGA3dFogMode;
+
+/*
+ * Uniquely identify one image (a 1D/2D/3D array) from a surface. This
+ * is a surface ID as well as face/mipmap indices.
+ */
+
+typedef
+struct SVGA3dSurfaceImageId {
+   uint32               sid;
+   uint32               face;
+   uint32               mipmap;
+} SVGA3dSurfaceImageId;
+
+typedef
+struct SVGA3dGuestImage {
+   SVGAGuestPtr         ptr;
+
+   /*
+    * A note on interpretation of pitch: This value of pitch is the
+    * number of bytes between vertically adjacent image
+    * blocks. Normally this is the number of bytes between the first
+    * pixel of two adjacent scanlines. With compressed textures,
+    * however, this may represent the number of bytes between
+    * compression blocks rather than between rows of pixels.
+    *
+    * XXX: Compressed textures currently must be tightly packed in guest memory.
+    *
+    * If the image is 1-dimensional, pitch is ignored.
+    *
+    * If 'pitch' is zero, the SVGA3D device calculates a pitch value
+    * assuming each row of blocks is tightly packed.
+    */
+   uint32 pitch;
+} SVGA3dGuestImage;
+
+
+/*
+ * FIFO command format definitions:
+ */
+
+/*
+ * The data size header following cmdNum for every 3d command
+ */
+typedef
+struct {
+   uint32               id;
+   uint32               size;
+} SVGA3dCmdHeader;
+
+/*
+ * A surface is a hierarchy of host VRAM surfaces: 1D, 2D, or 3D, with
+ * optional mipmaps and cube faces.
+ */
+
+typedef
+struct {
+   uint32               width;
+   uint32               height;
+   uint32               depth;
+} SVGA3dSize;
+
+typedef enum {
+   SVGA3D_SURFACE_CUBEMAP              = (1 << 0),
+   SVGA3D_SURFACE_HINT_STATIC          = (1 << 1),
+   SVGA3D_SURFACE_HINT_DYNAMIC         = (1 << 2),
+   SVGA3D_SURFACE_HINT_INDEXBUFFER     = (1 << 3),
+   SVGA3D_SURFACE_HINT_VERTEXBUFFER    = (1 << 4),
+   SVGA3D_SURFACE_HINT_TEXTURE         = (1 << 5),
+   SVGA3D_SURFACE_HINT_RENDERTARGET    = (1 << 6),
+   SVGA3D_SURFACE_HINT_DEPTHSTENCIL    = (1 << 7),
+   SVGA3D_SURFACE_HINT_WRITEONLY       = (1 << 8),
+} SVGA3dSurfaceFlags;
+
+typedef
+struct {
+   uint32               numMipLevels;
+} SVGA3dSurfaceFace;
+
+typedef
+struct {
+   uint32                      sid;
+   SVGA3dSurfaceFlags          surfaceFlags;
+   SVGA3dSurfaceFormat         format;
+   SVGA3dSurfaceFace           face[SVGA3D_MAX_SURFACE_FACES];
+   /*
+    * Followed by an SVGA3dSize structure for each mip level in each face.
+    *
+    * A note on surface sizes: Sizes are always specified in pixels,
+    * even if the true surface size is not a multiple of the minimum
+    * block size of the surface's format. For example, a 3x3x1 DXT1
+    * compressed texture would actually be stored as a 4x4x1 image in
+    * memory.
+    */
+} SVGA3dCmdDefineSurface;       /* SVGA_3D_CMD_SURFACE_DEFINE */
+
+typedef
+struct {
+   uint32               sid;
+} SVGA3dCmdDestroySurface;      /* SVGA_3D_CMD_SURFACE_DESTROY */
+
+typedef
+struct {
+   uint32               cid;
+} SVGA3dCmdDefineContext;       /* SVGA_3D_CMD_CONTEXT_DEFINE */
+
+typedef
+struct {
+   uint32               cid;
+} SVGA3dCmdDestroyContext;      /* SVGA_3D_CMD_CONTEXT_DESTROY */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dClearFlag      clearFlag;
+   uint32               color;
+   float                depth;
+   uint32               stencil;
+   /* Followed by variable number of SVGA3dRect structures */
+} SVGA3dCmdClear;               /* SVGA_3D_CMD_CLEAR */
+
+typedef
+struct SVGA3dCopyRect {
+   uint32               x;
+   uint32               y;
+   uint32               w;
+   uint32               h;
+   uint32               srcx;
+   uint32               srcy;
+} SVGA3dCopyRect;
+
+typedef
+struct SVGA3dCopyBox {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+   uint32               w;
+   uint32               h;
+   uint32               d;
+   uint32               srcx;
+   uint32               srcy;
+   uint32               srcz;
+} SVGA3dCopyBox;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               w;
+   uint32               h;
+} SVGA3dRect;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+   uint32               w;
+   uint32               h;
+   uint32               d;
+} SVGA3dBox;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+} SVGA3dPoint;
+
+typedef
+struct {
+   SVGA3dLightType      type;
+   SVGA3dBool           inWorldSpace;
+   float                diffuse[4];
+   float                specular[4];
+   float                ambient[4];
+   float                position[4];
+   float                direction[4];
+   float                range;
+   float                falloff;
+   float                attenuation0;
+   float                attenuation1;
+   float                attenuation2;
+   float                theta;
+   float                phi;
+} SVGA3dLightData;
+
+typedef
+struct {
+   uint32               sid;
+   /* Followed by variable number of SVGA3dCopyRect structures */
+} SVGA3dCmdPresent;             /* SVGA_3D_CMD_PRESENT */
+
+typedef
+struct {
+   SVGA3dRenderStateName   state;
+   union {
+      uint32               uintValue;
+      float                floatValue;
+   };
+} SVGA3dRenderState;
+
+typedef
+struct {
+   uint32               cid;
+   /* Followed by variable number of SVGA3dRenderState structures */
+} SVGA3dCmdSetRenderState;      /* SVGA_3D_CMD_SETRENDERSTATE */
+
+typedef
+struct {
+   uint32                 cid;
+   SVGA3dRenderTargetType type;
+   SVGA3dSurfaceImageId   target;
+} SVGA3dCmdSetRenderTarget;     /* SVGA_3D_CMD_SETRENDERTARGET */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId  src;
+   SVGA3dSurfaceImageId  dest;
+   /* Followed by variable number of SVGA3dCopyBox structures */
+} SVGA3dCmdSurfaceCopy;               /* SVGA_3D_CMD_SURFACE_COPY */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId  src;
+   SVGA3dSurfaceImageId  dest;
+   SVGA3dBox             boxSrc;
+   SVGA3dBox             boxDest;
+   SVGA3dStretchBltMode  mode;
+} SVGA3dCmdSurfaceStretchBlt;         /* SVGA_3D_CMD_SURFACE_STRETCHBLT */
+
+typedef
+struct {
+   /*
+    * If the discard flag is present in a surface DMA operation, the host may
+    * discard the contents of the current mipmap level and face of the target
+    * surface before applying the surface DMA contents.
+    */
+   uint32 discard : 1;
+
+   /*
+    * If the unsynchronized flag is present, the host may perform this upload
+    * without syncing to pending reads on this surface.
+    */
+   uint32 unsynchronized : 1;
+
+   /*
+    * Guests *MUST* set the reserved bits to 0 before submitting the command
+    * suffix as future flags may occupy these bits.
+    */
+   uint32 reserved : 30;
+} SVGA3dSurfaceDMAFlags;
+
+typedef
+struct {
+   SVGA3dGuestImage      guest;
+   SVGA3dSurfaceImageId  host;
+   SVGA3dTransferType    transfer;
+   /*
+    * Followed by variable number of SVGA3dCopyBox structures. For consistency
+    * in all clipping logic and coordinate translation, we define the
+    * "source" in each copyBox as the guest image and the
+    * "destination" as the host image, regardless of transfer
+    * direction.
+    *
+    * For efficiency, the SVGA3D device is free to copy more data than
+    * specified. For example, it may round copy boxes outwards such
+    * that they lie on particular alignment boundaries.
+    */
+} SVGA3dCmdSurfaceDMA;                /* SVGA_3D_CMD_SURFACE_DMA */
+
+/*
+ * SVGA3dCmdSurfaceDMASuffix --
+ *
+ *    This is a command suffix that will appear after a SurfaceDMA command in
+ *    the FIFO.  It contains some extra information that hosts may use to
+ *    optimize performance or protect the guest.  This suffix exists to preserve
+ *    backwards compatibility while also allowing for new functionality to be
+ *    implemented.
+ */
+
+typedef
+struct {
+   uint32 suffixSize;
+
+   /*
+    * The maximum offset is used to determine the maximum offset from the
+    * guestPtr base address that will be accessed or written to during this
+    * surfaceDMA.  If the suffix is supported, the host will respect this
+    * boundary while performing surface DMAs.
+    *
+    * Defaults to MAX_UINT32
+    */
+   uint32 maximumOffset;
+
+   /*
+    * A set of flags that describes optimizations that the host may perform
+    * while performing this surface DMA operation.  The guest should never rely
+    * on behaviour that is different when these flags are set for correctness.
+    *
+    * Defaults to 0
+    */
+   SVGA3dSurfaceDMAFlags flags;
+} SVGA3dCmdSurfaceDMASuffix;
+
+/*
+ * SVGA_3D_CMD_DRAW_PRIMITIVES --
+ *
+ *   This command is the SVGA3D device's generic drawing entry point.
+ *   It can draw multiple ranges of primitives, optionally using an
+ *   index buffer, using an arbitrary collection of vertex buffers.
+ *
+ *   Each SVGA3dVertexDecl defines a distinct vertex array to bind
+ *   during this draw call. The declarations specify which surface
+ *   the vertex data lives in, what that vertex data is used for,
+ *   and how to interpret it.
+ *
+ *   Each SVGA3dPrimitiveRange defines a collection of primitives
+ *   to render using the same vertex arrays. An index buffer is
+ *   optional.
+ */
+
+typedef
+struct {
+   /*
+    * A range hint is an optional specification for the range of indices
+    * in an SVGA3dArray that will be used. If 'last' is zero, it is assumed
+    * that the entire array will be used.
+    *
+    * These are only hints. The SVGA3D device may use them for
+    * performance optimization if possible, but it's also allowed to
+    * ignore these values.
+    */
+   uint32               first;
+   uint32               last;
+} SVGA3dArrayRangeHint;
+
+typedef
+struct {
+   /*
+    * Define the origin and shape of a vertex or index array. Both
+    * 'offset' and 'stride' are in bytes. The provided surface will be
+    * reinterpreted as a flat array of bytes in the same format used
+    * by surface DMA operations. To avoid unnecessary conversions, the
+    * surface should be created with the SVGA3D_BUFFER format.
+    *
+    * Index 0 in the array starts 'offset' bytes into the surface.
+    * Index 1 begins at byte 'offset + stride', etc. Array indices may
+    * not be negative.
+    */
+   uint32               surfaceId;
+   uint32               offset;
+   uint32               stride;
+} SVGA3dArray;
+
+typedef
+struct {
+   /*
+    * Describe a vertex array's data type, and define how it is to be
+    * used by the fixed function pipeline or the vertex shader. It
+    * isn't useful to have two VertexDecls with the same
+    * VertexArrayIdentity in one draw call.
+    */
+   SVGA3dDeclType       type;
+   SVGA3dDeclMethod     method;
+   SVGA3dDeclUsage      usage;
+   uint32               usageIndex;
+} SVGA3dVertexArrayIdentity;
+
+typedef
+struct {
+   SVGA3dVertexArrayIdentity  identity;
+   SVGA3dArray                array;
+   SVGA3dArrayRangeHint       rangeHint;
+} SVGA3dVertexDecl;
+
+typedef
+struct {
+   /*
+    * Define a group of primitives to render, from sequential indices.
+    *
+    * The value of 'primitiveType' and 'primitiveCount' imply the
+    * total number of vertices that will be rendered.
+    */
+   SVGA3dPrimitiveType  primType;
+   uint32               primitiveCount;
+
+   /*
+    * Optional index buffer. If indexArray.surfaceId is
+    * SVGA3D_INVALID_ID, we render without an index buffer. Rendering
+    * without an index buffer is identical to rendering with an index
+    * buffer containing the sequence [0, 1, 2, 3, ...].
+    *
+    * If an index buffer is in use, indexWidth specifies the width in
+    * bytes of each index value. It must be less than or equal to
+    * indexArray.stride.
+    *
+    * (Currently, the SVGA3D device requires index buffers to be tightly
+    * packed. In other words, indexWidth == indexArray.stride)
+    */
+   SVGA3dArray          indexArray;
+   uint32               indexWidth;
+
+   /*
+    * Optional index bias. This number is added to all indices from
+    * indexArray before they are used as vertex array indices. This
+    * can be used in multiple ways:
+    *
+    *  - When not using an indexArray, this bias can be used to
+    *    specify where in the vertex arrays to begin rendering.
+    *
+    *  - A positive number here is equivalent to increasing the
+    *    offset in each vertex array.
+    *
+    *  - A negative number can be used to render using a small
+    *    vertex array and an index buffer that contains large
+    *    values. This may be used by some applications that
+    *    crop a vertex buffer without modifying their index
+    *    buffer.
+    *
+    * Note that rendering with a negative bias value may be slower and
+    * use more memory than rendering with a positive or zero bias.
+    */
+   int32                indexBias;
+} SVGA3dPrimitiveRange;
+
+typedef
+struct {
+   uint32               cid;
+   uint32               numVertexDecls;
+   uint32               numRanges;
+
+   /*
+    * There are two variable size arrays after the
+    * SVGA3dCmdDrawPrimitives structure. In order,
+    * they are:
+    *
+    * 1. SVGA3dVertexDecl, quantity 'numVertexDecls'
+    * 2. SVGA3dPrimitiveRange, quantity 'numRanges'
+    * 3. Optionally, SVGA3dVertexDivisor, quantity 'numVertexDecls' (contains
+    *    the frequency divisor for this the corresponding vertex decl)
+    */
+} SVGA3dCmdDrawPrimitives;      /* SVGA_3D_CMD_DRAWPRIMITIVES */
+
+typedef
+struct {
+   uint32                   stage;
+   SVGA3dTextureStateName   name;
+   union {
+      uint32                value;
+      float                 floatValue;
+   };
+} SVGA3dTextureState;
+
+typedef
+struct {
+   uint32               cid;
+   /* Followed by variable number of SVGA3dTextureState structures */
+} SVGA3dCmdSetTextureState;      /* SVGA_3D_CMD_SETTEXTURESTATE */
+
+typedef
+struct {
+   uint32                   cid;
+   SVGA3dTransformType      type;
+   float                    matrix[16];
+} SVGA3dCmdSetTransform;          /* SVGA_3D_CMD_SETTRANSFORM */
+
+typedef
+struct {
+   float                min;
+   float                max;
+} SVGA3dZRange;
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dZRange         zRange;
+} SVGA3dCmdSetZRange;             /* SVGA_3D_CMD_SETZRANGE */
+
+typedef
+struct {
+   float                diffuse[4];
+   float                ambient[4];
+   float                specular[4];
+   float                emissive[4];
+   float                shininess;
+} SVGA3dMaterial;
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dFace           face;
+   SVGA3dMaterial       material;
+} SVGA3dCmdSetMaterial;           /* SVGA_3D_CMD_SETMATERIAL */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   SVGA3dLightData      data;
+} SVGA3dCmdSetLightData;           /* SVGA_3D_CMD_SETLIGHTDATA */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   uint32               enabled;
+} SVGA3dCmdSetLightEnabled;      /* SVGA_3D_CMD_SETLIGHTENABLED */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dRect           rect;
+} SVGA3dCmdSetViewport;           /* SVGA_3D_CMD_SETVIEWPORT */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dRect           rect;
+} SVGA3dCmdSetScissorRect;         /* SVGA_3D_CMD_SETSCISSORRECT */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   float                plane[4];
+} SVGA3dCmdSetClipPlane;           /* SVGA_3D_CMD_SETCLIPPLANE */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               shid;
+   SVGA3dShaderType     type;
+   /* Followed by variable number of DWORDs for shader bycode */
+} SVGA3dCmdDefineShader;           /* SVGA_3D_CMD_SHADER_DEFINE */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               shid;
+   SVGA3dShaderType     type;
+} SVGA3dCmdDestroyShader;         /* SVGA_3D_CMD_SHADER_DESTROY */
+
+typedef
+struct {
+   uint32                  cid;
+   uint32                  reg;     /* register number */
+   SVGA3dShaderType        type;
+   SVGA3dShaderConstType   ctype;
+   uint32                  values[4];
+} SVGA3dCmdSetShaderConst;        /* SVGA_3D_CMD_SET_SHADER_CONST */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dShaderType     type;
+   uint32               shid;
+} SVGA3dCmdSetShader;             /* SVGA_3D_CMD_SET_SHADER */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+} SVGA3dCmdBeginQuery;           /* SVGA_3D_CMD_BEGIN_QUERY */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+   SVGAGuestPtr         guestResult;  /* Points to an SVGA3dQueryResult structure */
+} SVGA3dCmdEndQuery;                  /* SVGA_3D_CMD_END_QUERY */
+
+typedef
+struct {
+   uint32               cid;          /* Same parameters passed to END_QUERY */
+   SVGA3dQueryType      type;
+   SVGAGuestPtr         guestResult;
+} SVGA3dCmdWaitForQuery;              /* SVGA_3D_CMD_WAIT_FOR_QUERY */
+
+typedef
+struct {
+   uint32               totalSize;    /* Set by guest before query is ended. */
+   SVGA3dQueryState     state;        /* Set by host or guest. See SVGA3dQueryState. */
+   union {                            /* Set by host on exit from PENDING state */
+      uint32            result32;
+   };
+} SVGA3dQueryResult;
+
+/*
+ * SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN --
+ *
+ *    This is a blit from an SVGA3D surface to a Screen Object. Just
+ *    like GMR-to-screen blits, this blit may be directed at a
+ *    specific screen or to the virtual coordinate space.
+ *
+ *    The blit copies from a rectangular region of an SVGA3D surface
+ *    image to a rectangular region of a screen or screens.
+ *
+ *    This command takes an optional variable-length list of clipping
+ *    rectangles after the body of the command. If no rectangles are
+ *    specified, there is no clipping region. The entire destRect is
+ *    drawn to. If one or more rectangles are included, they describe
+ *    a clipping region. The clip rectangle coordinates are measured
+ *    relative to the top-left corner of destRect.
+ *
+ *    This clipping region serves multiple purposes:
+ *
+ *      - It can be used to perform an irregularly shaped blit more
+ *        efficiently than by issuing many separate blit commands.
+ *
+ *      - It is equivalent to allowing blits with non-integer
+ *        source coordinates. You could blit just one half-pixel
+ *        of a source, for example, by specifying a larger
+ *        destination rectangle than you need, then removing
+ *        part of it using a clip rectangle.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ *
+ * Limitations:
+ *
+ *    - Currently, no backend supports blits from a mipmap or face
+ *      other than the first one.
+ */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId srcImage;
+   SVGASignedRect       srcRect;
+   uint32               destScreenId; /* Screen ID or SVGA_ID_INVALID for virt. coords */
+   SVGASignedRect       destRect;     /* Supports scaling if src/rest different size */
+   /* Clipping: zero or more SVGASignedRects follow */
+} SVGA3dCmdBlitSurfaceToScreen;         /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */
+
+
+/*
+ * Capability query index.
+ *
+ * Notes:
+ *
+ *   1. SVGA3D_DEVCAP_MAX_TEXTURES reflects the maximum number of
+ *      fixed-function texture units available. Each of these units
+ *      work in both FFP and Shader modes, and they support texture
+ *      transforms and texture coordinates. The host may have additional
+ *      texture image units that are only usable with shaders.
+ *
+ *   2. The BUFFER_FORMAT capabilities are deprecated, and they always
+ *      return TRUE. Even on physical hardware that does not support
+ *      these formats natively, the SVGA3D device will provide an emulation
+ *      which should be invisible to the guest OS.
+ *
+ *      In general, the SVGA3D device should support any operation on
+ *      any surface format, it just may perform some of these
+ *      operations in software depending on the capabilities of the
+ *      available physical hardware.
+ *
+ *      XXX: In the future, we will add capabilities that describe in
+ *      detail what formats are supported in hardware for what kinds
+ *      of operations.
+ */
+
+typedef enum {
+   SVGA3D_DEVCAP_3D                                = 0,
+   SVGA3D_DEVCAP_MAX_LIGHTS                        = 1,
+   SVGA3D_DEVCAP_MAX_TEXTURES                      = 2,  /* See note (1) */
+   SVGA3D_DEVCAP_MAX_CLIP_PLANES                   = 3,
+   SVGA3D_DEVCAP_VERTEX_SHADER_VERSION             = 4,
+   SVGA3D_DEVCAP_VERTEX_SHADER                     = 5,
+   SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION           = 6,
+   SVGA3D_DEVCAP_FRAGMENT_SHADER                   = 7,
+   SVGA3D_DEVCAP_MAX_RENDER_TARGETS                = 8,
+   SVGA3D_DEVCAP_S23E8_TEXTURES                    = 9,
+   SVGA3D_DEVCAP_S10E5_TEXTURES                    = 10,
+   SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND             = 11,
+   SVGA3D_DEVCAP_D16_BUFFER_FORMAT                 = 12, /* See note (2) */
+   SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT               = 13, /* See note (2) */
+   SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT               = 14, /* See note (2) */
+   SVGA3D_DEVCAP_QUERY_TYPES                       = 15,
+   SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING         = 16,
+   SVGA3D_DEVCAP_MAX_POINT_SIZE                    = 17,
+   SVGA3D_DEVCAP_MAX_SHADER_TEXTURES               = 18,
+   SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH                 = 19,
+   SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT                = 20,
+   SVGA3D_DEVCAP_MAX_VOLUME_EXTENT                 = 21,
+   SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT                = 22,
+   SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO          = 23,
+   SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY            = 24,
+   SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT               = 25,
+   SVGA3D_DEVCAP_MAX_VERTEX_INDEX                  = 26,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS    = 27,
+   SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS  = 28,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS           = 29,
+   SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS         = 30,
+   SVGA3D_DEVCAP_TEXTURE_OPS                       = 31,
+   SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8               = 32,
+   SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8               = 33,
+   SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10            = 34,
+   SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5               = 35,
+   SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5               = 36,
+   SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4               = 37,
+   SVGA3D_DEVCAP_SURFACEFMT_R5G6B5                 = 38,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16            = 39,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8      = 40,
+   SVGA3D_DEVCAP_SURFACEFMT_ALPHA8                 = 41,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8             = 42,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D16                  = 43,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8                = 44,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8                = 45,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT1                   = 46,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT2                   = 47,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT3                   = 48,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT4                   = 49,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT5                   = 50,
+   SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8           = 51,
+   SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10            = 52,
+   SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8               = 53,
+   SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8               = 54,
+   SVGA3D_DEVCAP_SURFACEFMT_CxV8U8                 = 55,
+   SVGA3D_DEVCAP_SURFACEFMT_R_S10E5                = 56,
+   SVGA3D_DEVCAP_SURFACEFMT_R_S23E8                = 57,
+   SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5               = 58,
+   SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8               = 59,
+   SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5             = 60,
+   SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8             = 61,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES        = 63,
+
+   /*
+    * Note that MAX_SIMULTANEOUS_RENDER_TARGETS is a maximum count of color
+    * render targets.  This does no include the depth or stencil targets.
+    */
+   SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS   = 64,
+
+   SVGA3D_DEVCAP_SURFACEFMT_V16U16                 = 65,
+   SVGA3D_DEVCAP_SURFACEFMT_G16R16                 = 66,
+   SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16           = 67,
+   SVGA3D_DEVCAP_SURFACEFMT_UYVY                   = 68,
+   SVGA3D_DEVCAP_SURFACEFMT_YUY2                   = 69,
+
+   /*
+    * Don't add new caps into the previous section; the values in this
+    * enumeration must not change. You can put new values right before
+    * SVGA3D_DEVCAP_MAX.
+    */
+   SVGA3D_DEVCAP_MAX                                  /* This must be the last index. */
+} SVGA3dDevCapIndex;
+
+typedef union {
+   Bool   b;
+   uint32 u;
+   int32  i;
+   float  f;
+} SVGA3dDevCapResult;
+
+#endif /* _SVGA3D_REG_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/svga_escape.h b/drivers/gpu/drm/vmwgfx/svga_escape.h
new file mode 100644 (file)
index 0000000..7b85e9b
--- /dev/null
@@ -0,0 +1,89 @@
+/**********************************************************
+ * Copyright 2007-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_escape.h --
+ *
+ *    Definitions for our own (vendor-specific) SVGA Escape commands.
+ */
+
+#ifndef _SVGA_ESCAPE_H_
+#define _SVGA_ESCAPE_H_
+
+
+/*
+ * Namespace IDs for the escape command
+ */
+
+#define SVGA_ESCAPE_NSID_VMWARE 0x00000000
+#define SVGA_ESCAPE_NSID_DEVEL  0xFFFFFFFF
+
+
+/*
+ * Within SVGA_ESCAPE_NSID_VMWARE, we multiplex commands according to
+ * the first DWORD of escape data (after the nsID and size). As a
+ * guideline we're using the high word and low word as a major and
+ * minor command number, respectively.
+ *
+ * Major command number allocation:
+ *
+ *   0000: Reserved
+ *   0001: SVGA_ESCAPE_VMWARE_LOG (svga_binary_logger.h)
+ *   0002: SVGA_ESCAPE_VMWARE_VIDEO (svga_overlay.h)
+ *   0003: SVGA_ESCAPE_VMWARE_HINT (svga_escape.h)
+ */
+
+#define SVGA_ESCAPE_VMWARE_MAJOR_MASK  0xFFFF0000
+
+
+/*
+ * SVGA Hint commands.
+ *
+ * These escapes let the SVGA driver provide optional information to
+ * he host about the state of the guest or guest applications. The
+ * host can use these hints to make user interface or performance
+ * decisions.
+ *
+ * Notes:
+ *
+ *   - SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN is deprecated for guests
+ *     that use the SVGA Screen Object extension. Instead of sending
+ *     this escape, use the SVGA_SCREEN_FULLSCREEN_HINT flag on your
+ *     Screen Object.
+ */
+
+#define SVGA_ESCAPE_VMWARE_HINT               0x00030000
+#define SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN    0x00030001  // Deprecated
+
+typedef
+struct {
+   uint32 command;
+   uint32 fullscreen;
+   struct {
+      int32 x, y;
+   } monitorPosition;
+} SVGAEscapeHintFullscreen;
+
+#endif /* _SVGA_ESCAPE_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/svga_overlay.h b/drivers/gpu/drm/vmwgfx/svga_overlay.h
new file mode 100644 (file)
index 0000000..f753d73
--- /dev/null
@@ -0,0 +1,201 @@
+/**********************************************************
+ * Copyright 2007-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_overlay.h --
+ *
+ *    Definitions for video-overlay support.
+ */
+
+#ifndef _SVGA_OVERLAY_H_
+#define _SVGA_OVERLAY_H_
+
+#include "svga_reg.h"
+
+/*
+ * Video formats we support
+ */
+
+#define VMWARE_FOURCC_YV12 0x32315659 // 'Y' 'V' '1' '2'
+#define VMWARE_FOURCC_YUY2 0x32595559 // 'Y' 'U' 'Y' '2'
+#define VMWARE_FOURCC_UYVY 0x59565955 // 'U' 'Y' 'V' 'Y'
+
+typedef enum {
+   SVGA_OVERLAY_FORMAT_INVALID = 0,
+   SVGA_OVERLAY_FORMAT_YV12 = VMWARE_FOURCC_YV12,
+   SVGA_OVERLAY_FORMAT_YUY2 = VMWARE_FOURCC_YUY2,
+   SVGA_OVERLAY_FORMAT_UYVY = VMWARE_FOURCC_UYVY,
+} SVGAOverlayFormat;
+
+#define SVGA_VIDEO_COLORKEY_MASK             0x00ffffff
+
+#define SVGA_ESCAPE_VMWARE_VIDEO             0x00020000
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS    0x00020001
+        /* FIFO escape layout:
+         * Type, Stream Id, (Register Id, Value) pairs */
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_FLUSH       0x00020002
+        /* FIFO escape layout:
+         * Type, Stream Id */
+
+typedef
+struct SVGAEscapeVideoSetRegs {
+   struct {
+      uint32 cmdType;
+      uint32 streamId;
+   } header;
+
+   // May include zero or more items.
+   struct {
+      uint32 registerId;
+      uint32 value;
+   } items[1];
+} SVGAEscapeVideoSetRegs;
+
+typedef
+struct SVGAEscapeVideoFlush {
+   uint32 cmdType;
+   uint32 streamId;
+} SVGAEscapeVideoFlush;
+
+
+/*
+ * Struct definitions for the video overlay commands built on
+ * SVGAFifoCmdEscape.
+ */
+typedef
+struct {
+   uint32 command;
+   uint32 overlay;
+} SVGAFifoEscapeCmdVideoBase;
+
+typedef
+struct {
+   SVGAFifoEscapeCmdVideoBase videoCmd;
+} SVGAFifoEscapeCmdVideoFlush;
+
+typedef
+struct {
+   SVGAFifoEscapeCmdVideoBase videoCmd;
+   struct {
+      uint32 regId;
+      uint32 value;
+   } items[1];
+} SVGAFifoEscapeCmdVideoSetRegs;
+
+typedef
+struct {
+   SVGAFifoEscapeCmdVideoBase videoCmd;
+   struct {
+      uint32 regId;
+      uint32 value;
+   } items[SVGA_VIDEO_NUM_REGS];
+} SVGAFifoEscapeCmdVideoSetAllRegs;
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMwareVideoGetAttributes --
+ *
+ *      Computes the size, pitches and offsets for YUV frames.
+ *
+ * Results:
+ *      TRUE on success; otherwise FALSE on failure.
+ *
+ * Side effects:
+ *      Pitches and offsets for the given YUV frame are put in 'pitches'
+ *      and 'offsets' respectively. They are both optional though.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static inline bool
+VMwareVideoGetAttributes(const SVGAOverlayFormat format,    // IN
+                         uint32 *width,                     // IN / OUT
+                         uint32 *height,                    // IN / OUT
+                         uint32 *size,                      // OUT
+                         uint32 *pitches,                   // OUT (optional)
+                         uint32 *offsets)                   // OUT (optional)
+{
+    int tmp;
+
+    *width = (*width + 1) & ~1;
+
+    if (offsets) {
+        offsets[0] = 0;
+    }
+
+    switch (format) {
+    case VMWARE_FOURCC_YV12:
+       *height = (*height + 1) & ~1;
+       *size = (*width + 3) & ~3;
+
+       if (pitches) {
+          pitches[0] = *size;
+       }
+
+       *size *= *height;
+
+       if (offsets) {
+          offsets[1] = *size;
+       }
+
+       tmp = ((*width >> 1) + 3) & ~3;
+
+       if (pitches) {
+          pitches[1] = pitches[2] = tmp;
+       }
+
+       tmp *= (*height >> 1);
+       *size += tmp;
+
+       if (offsets) {
+          offsets[2] = *size;
+       }
+
+       *size += tmp;
+       break;
+
+    case VMWARE_FOURCC_YUY2:
+    case VMWARE_FOURCC_UYVY:
+       *size = *width * 2;
+
+       if (pitches) {
+          pitches[0] = *size;
+       }
+
+       *size *= *height;
+       break;
+
+    default:
+       return false;
+    }
+
+    return true;
+}
+
+#endif // _SVGA_OVERLAY_H_
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h
new file mode 100644 (file)
index 0000000..1b96c2e
--- /dev/null
@@ -0,0 +1,1346 @@
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga_reg.h --
+ *
+ *    Virtual hardware definitions for the VMware SVGA II device.
+ */
+
+#ifndef _SVGA_REG_H_
+#define _SVGA_REG_H_
+
+/*
+ * PCI device IDs.
+ */
+#define PCI_VENDOR_ID_VMWARE            0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2      0x0405
+
+/*
+ * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
+ * cursor bypass mode. This is still supported, but no new guest
+ * drivers should use it.
+ */
+#define SVGA_CURSOR_ON_HIDE            0x0   /* Must be 0 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_SHOW            0x1   /* Must be 1 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_REMOVE_FROM_FB  0x2   /* Remove the cursor from the framebuffer because we need to see what's under it */
+#define SVGA_CURSOR_ON_RESTORE_TO_FB   0x3   /* Put the cursor back in the framebuffer so the user can see it */
+
+/*
+ * The maximum framebuffer size that can traced for e.g. guests in VESA mode.
+ * The changeMap in the monitor is proportional to this number. Therefore, we'd
+ * like to keep it as small as possible to reduce monitor overhead (using
+ * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area by over
+ * 4k!).
+ *
+ * NB: For compatibility reasons, this value must be greater than 0xff0000.
+ *     See bug 335072.
+ */
+#define SVGA_FB_MAX_TRACEABLE_SIZE      0x1000000
+
+#define SVGA_MAX_PSEUDOCOLOR_DEPTH      8
+#define SVGA_MAX_PSEUDOCOLORS           (1 << SVGA_MAX_PSEUDOCOLOR_DEPTH)
+#define SVGA_NUM_PALETTE_REGS           (3 * SVGA_MAX_PSEUDOCOLORS)
+
+#define SVGA_MAGIC         0x900000UL
+#define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))
+
+/* Version 2 let the address of the frame buffer be unsigned on Win32 */
+#define SVGA_VERSION_2     2
+#define SVGA_ID_2          SVGA_MAKE_ID(SVGA_VERSION_2)
+
+/* Version 1 has new registers starting with SVGA_REG_CAPABILITIES so
+   PALETTE_BASE has moved */
+#define SVGA_VERSION_1     1
+#define SVGA_ID_1          SVGA_MAKE_ID(SVGA_VERSION_1)
+
+/* Version 0 is the initial version */
+#define SVGA_VERSION_0     0
+#define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
+
+/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */
+#define SVGA_ID_INVALID    0xFFFFFFFF
+
+/* Port offsets, relative to BAR0 */
+#define SVGA_INDEX_PORT         0x0
+#define SVGA_VALUE_PORT         0x1
+#define SVGA_BIOS_PORT          0x2
+#define SVGA_IRQSTATUS_PORT     0x8
+
+/*
+ * Interrupt source flags for IRQSTATUS_PORT and IRQMASK.
+ *
+ * Interrupts are only supported when the
+ * SVGA_CAP_IRQMASK capability is present.
+ */
+#define SVGA_IRQFLAG_ANY_FENCE            0x1    /* Any fence was passed */
+#define SVGA_IRQFLAG_FIFO_PROGRESS        0x2    /* Made forward progress in the FIFO */
+#define SVGA_IRQFLAG_FENCE_GOAL           0x4    /* SVGA_FIFO_FENCE_GOAL reached */
+
+/*
+ * Registers
+ */
+
+enum {
+   SVGA_REG_ID = 0,
+   SVGA_REG_ENABLE = 1,
+   SVGA_REG_WIDTH = 2,
+   SVGA_REG_HEIGHT = 3,
+   SVGA_REG_MAX_WIDTH = 4,
+   SVGA_REG_MAX_HEIGHT = 5,
+   SVGA_REG_DEPTH = 6,
+   SVGA_REG_BITS_PER_PIXEL = 7,       /* Current bpp in the guest */
+   SVGA_REG_PSEUDOCOLOR = 8,
+   SVGA_REG_RED_MASK = 9,
+   SVGA_REG_GREEN_MASK = 10,
+   SVGA_REG_BLUE_MASK = 11,
+   SVGA_REG_BYTES_PER_LINE = 12,
+   SVGA_REG_FB_START = 13,            /* (Deprecated) */
+   SVGA_REG_FB_OFFSET = 14,
+   SVGA_REG_VRAM_SIZE = 15,
+   SVGA_REG_FB_SIZE = 16,
+
+   /* ID 0 implementation only had the above registers, then the palette */
+
+   SVGA_REG_CAPABILITIES = 17,
+   SVGA_REG_MEM_START = 18,           /* (Deprecated) */
+   SVGA_REG_MEM_SIZE = 19,
+   SVGA_REG_CONFIG_DONE = 20,         /* Set when memory area configured */
+   SVGA_REG_SYNC = 21,                /* See "FIFO Synchronization Registers" */
+   SVGA_REG_BUSY = 22,                /* See "FIFO Synchronization Registers" */
+   SVGA_REG_GUEST_ID = 23,            /* Set guest OS identifier */
+   SVGA_REG_CURSOR_ID = 24,           /* (Deprecated) */
+   SVGA_REG_CURSOR_X = 25,            /* (Deprecated) */
+   SVGA_REG_CURSOR_Y = 26,            /* (Deprecated) */
+   SVGA_REG_CURSOR_ON = 27,           /* (Deprecated) */
+   SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* (Deprecated) */
+   SVGA_REG_SCRATCH_SIZE = 29,        /* Number of scratch registers */
+   SVGA_REG_MEM_REGS = 30,            /* Number of FIFO registers */
+   SVGA_REG_NUM_DISPLAYS = 31,        /* (Deprecated) */
+   SVGA_REG_PITCHLOCK = 32,           /* Fixed pitch for all modes */
+   SVGA_REG_IRQMASK = 33,             /* Interrupt mask */
+
+   /* Legacy multi-monitor support */
+   SVGA_REG_NUM_GUEST_DISPLAYS = 34,/* Number of guest displays in X/Y direction */
+   SVGA_REG_DISPLAY_ID = 35,        /* Display ID for the following display attributes */
+   SVGA_REG_DISPLAY_IS_PRIMARY = 36,/* Whether this is a primary display */
+   SVGA_REG_DISPLAY_POSITION_X = 37,/* The display position x */
+   SVGA_REG_DISPLAY_POSITION_Y = 38,/* The display position y */
+   SVGA_REG_DISPLAY_WIDTH = 39,     /* The display's width */
+   SVGA_REG_DISPLAY_HEIGHT = 40,    /* The display's height */
+
+   /* See "Guest memory regions" below. */
+   SVGA_REG_GMR_ID = 41,
+   SVGA_REG_GMR_DESCRIPTOR = 42,
+   SVGA_REG_GMR_MAX_IDS = 43,
+   SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
+
+   SVGA_REG_TRACES = 45,            /* Enable trace-based updates even when FIFO is on */
+   SVGA_REG_TOP = 46,               /* Must be 1 more than the last register */
+
+   SVGA_PALETTE_BASE = 1024,        /* Base of SVGA color map */
+   /* Next 768 (== 256*3) registers exist for colormap */
+
+   SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + SVGA_NUM_PALETTE_REGS
+                                    /* Base of scratch registers */
+   /* Next reg[SVGA_REG_SCRATCH_SIZE] registers exist for scratch usage:
+      First 4 are reserved for VESA BIOS Extension; any remaining are for
+      the use of the current SVGA driver. */
+};
+
+
+/*
+ * Guest memory regions (GMRs):
+ *
+ * This is a new memory mapping feature available in SVGA devices
+ * which have the SVGA_CAP_GMR bit set. Previously, there were two
+ * fixed memory regions available with which to share data between the
+ * device and the driver: the FIFO ('MEM') and the framebuffer. GMRs
+ * are our name for an extensible way of providing arbitrary DMA
+ * buffers for use between the driver and the SVGA device. They are a
+ * new alternative to framebuffer memory, usable for both 2D and 3D
+ * graphics operations.
+ *
+ * Since GMR mapping must be done synchronously with guest CPU
+ * execution, we use a new pair of SVGA registers:
+ *
+ *   SVGA_REG_GMR_ID --
+ *
+ *     Read/write.
+ *     This register holds the 32-bit ID (a small positive integer)
+ *     of a GMR to create, delete, or redefine. Writing this register
+ *     has no side-effects.
+ *
+ *   SVGA_REG_GMR_DESCRIPTOR --
+ *
+ *     Write-only.
+ *     Writing this register will create, delete, or redefine the GMR
+ *     specified by the above ID register. If this register is zero,
+ *     the GMR is deleted. Any pointers into this GMR (including those
+ *     currently being processed by FIFO commands) will be
+ *     synchronously invalidated.
+ *
+ *     If this register is nonzero, it must be the physical page
+ *     number (PPN) of a data structure which describes the physical
+ *     layout of the memory region this GMR should describe. The
+ *     descriptor structure will be read synchronously by the SVGA
+ *     device when this register is written. The descriptor need not
+ *     remain allocated for the lifetime of the GMR.
+ *
+ *     The guest driver should write SVGA_REG_GMR_ID first, then
+ *     SVGA_REG_GMR_DESCRIPTOR.
+ *
+ *   SVGA_REG_GMR_MAX_IDS --
+ *
+ *     Read-only.
+ *     The SVGA device may choose to support a maximum number of
+ *     user-defined GMR IDs. This register holds the number of supported
+ *     IDs. (The maximum supported ID plus 1)
+ *
+ *   SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH --
+ *
+ *     Read-only.
+ *     The SVGA device may choose to put a limit on the total number
+ *     of SVGAGuestMemDescriptor structures it will read when defining
+ *     a single GMR.
+ *
+ * The descriptor structure is an array of SVGAGuestMemDescriptor
+ * structures. Each structure may do one of three things:
+ *
+ *   - Terminate the GMR descriptor list.
+ *     (ppn==0, numPages==0)
+ *
+ *   - Add a PPN or range of PPNs to the GMR's virtual address space.
+ *     (ppn != 0, numPages != 0)
+ *
+ *   - Provide the PPN of the next SVGAGuestMemDescriptor, in order to
+ *     support multi-page GMR descriptor tables without forcing the
+ *     driver to allocate physically contiguous memory.
+ *     (ppn != 0, numPages == 0)
+ *
+ * Note that each physical page of SVGAGuestMemDescriptor structures
+ * can describe at least 2MB of guest memory. If the driver needs to
+ * use more than one page of descriptor structures, it must use one of
+ * its SVGAGuestMemDescriptors to point to an additional page.  The
+ * device will never automatically cross a page boundary.
+ *
+ * Once the driver has described a GMR, it is immediately available
+ * for use via any FIFO command that uses an SVGAGuestPtr structure.
+ * These pointers include a GMR identifier plus an offset into that
+ * GMR.
+ *
+ * The driver must check the SVGA_CAP_GMR bit before using the GMR
+ * registers.
+ */
+
+/*
+ * Special GMR IDs, allowing SVGAGuestPtrs to point to framebuffer
+ * memory as well.  In the future, these IDs could even be used to
+ * allow legacy memory regions to be redefined by the guest as GMRs.
+ *
+ * Using the guest framebuffer (GFB) at BAR1 for general purpose DMA
+ * is being phased out. Please try to use user-defined GMRs whenever
+ * possible.
+ */
+#define SVGA_GMR_NULL         ((uint32) -1)
+#define SVGA_GMR_FRAMEBUFFER  ((uint32) -2)  // Guest Framebuffer (GFB)
+
+typedef
+struct SVGAGuestMemDescriptor {
+   uint32 ppn;
+   uint32 numPages;
+} SVGAGuestMemDescriptor;
+
+typedef
+struct SVGAGuestPtr {
+   uint32 gmrId;
+   uint32 offset;
+} SVGAGuestPtr;
+
+
+/*
+ * SVGAGMRImageFormat --
+ *
+ *    This is a packed representation of the source 2D image format
+ *    for a GMR-to-screen blit. Currently it is defined as an encoding
+ *    of the screen's color depth and bits-per-pixel, however, 16 bits
+ *    are reserved for future use to identify other encodings (such as
+ *    RGBA or higher-precision images).
+ *
+ *    Currently supported formats:
+ *
+ *       bpp depth  Format Name
+ *       --- -----  -----------
+ *        32    24  32-bit BGRX
+ *        24    24  24-bit BGR
+ *        16    16  RGB 5-6-5
+ *        16    15  RGB 5-5-5
+ *
+ */
+
+typedef
+struct SVGAGMRImageFormat {
+   union {
+      struct {
+         uint32 bitsPerPixel : 8;
+         uint32 colorDepth   : 8;
+         uint32 reserved     : 16;  // Must be zero
+      };
+
+      uint32 value;
+   };
+} SVGAGMRImageFormat;
+
+/*
+ * SVGAColorBGRX --
+ *
+ *    A 24-bit color format (BGRX), which does not depend on the
+ *    format of the legacy guest framebuffer (GFB) or the current
+ *    GMRFB state.
+ */
+
+typedef
+struct SVGAColorBGRX {
+   union {
+      struct {
+         uint32 b : 8;
+         uint32 g : 8;
+         uint32 r : 8;
+         uint32 x : 8;  // Unused
+      };
+
+      uint32 value;
+   };
+} SVGAColorBGRX;
+
+
+/*
+ * SVGASignedRect --
+ * SVGASignedPoint --
+ *
+ *    Signed rectangle and point primitives. These are used by the new
+ *    2D primitives for drawing to Screen Objects, which can occupy a
+ *    signed virtual coordinate space.
+ *
+ *    SVGASignedRect specifies a half-open interval: the (left, top)
+ *    pixel is part of the rectangle, but the (right, bottom) pixel is
+ *    not.
+ */
+
+typedef
+struct SVGASignedRect {
+   int32  left;
+   int32  top;
+   int32  right;
+   int32  bottom;
+} SVGASignedRect;
+
+typedef
+struct SVGASignedPoint {
+   int32  x;
+   int32  y;
+} SVGASignedPoint;
+
+
+/*
+ *  Capabilities
+ *
+ *  Note the holes in the bitfield. Missing bits have been deprecated,
+ *  and must not be reused. Those capabilities will never be reported
+ *  by new versions of the SVGA device.
+ */
+
+#define SVGA_CAP_NONE               0x00000000
+#define SVGA_CAP_RECT_COPY          0x00000002
+#define SVGA_CAP_CURSOR             0x00000020
+#define SVGA_CAP_CURSOR_BYPASS      0x00000040   // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_CURSOR_BYPASS_2    0x00000080   // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_8BIT_EMULATION     0x00000100
+#define SVGA_CAP_ALPHA_CURSOR       0x00000200
+#define SVGA_CAP_3D                 0x00004000
+#define SVGA_CAP_EXTENDED_FIFO      0x00008000
+#define SVGA_CAP_MULTIMON           0x00010000   // Legacy multi-monitor support
+#define SVGA_CAP_PITCHLOCK          0x00020000
+#define SVGA_CAP_IRQMASK            0x00040000
+#define SVGA_CAP_DISPLAY_TOPOLOGY   0x00080000   // Legacy multi-monitor support
+#define SVGA_CAP_GMR                0x00100000
+#define SVGA_CAP_TRACES             0x00200000
+
+
+/*
+ * FIFO register indices.
+ *
+ * The FIFO is a chunk of device memory mapped into guest physmem.  It
+ * is always treated as 32-bit words.
+ *
+ * The guest driver gets to decide how to partition it between
+ * - FIFO registers (there are always at least 4, specifying where the
+ *   following data area is and how much data it contains; there may be
+ *   more registers following these, depending on the FIFO protocol
+ *   version in use)
+ * - FIFO data, written by the guest and slurped out by the VMX.
+ * These indices are 32-bit word offsets into the FIFO.
+ */
+
+enum {
+   /*
+    * Block 1 (basic registers): The originally defined FIFO registers.
+    * These exist and are valid for all versions of the FIFO protocol.
+    */
+
+   SVGA_FIFO_MIN = 0,
+   SVGA_FIFO_MAX,       /* The distance from MIN to MAX must be at least 10K */
+   SVGA_FIFO_NEXT_CMD,
+   SVGA_FIFO_STOP,
+
+   /*
+    * Block 2 (extended registers): Mandatory registers for the extended
+    * FIFO.  These exist if the SVGA caps register includes
+    * SVGA_CAP_EXTENDED_FIFO; some of them are valid only if their
+    * associated capability bit is enabled.
+    *
+    * Note that when originally defined, SVGA_CAP_EXTENDED_FIFO implied
+    * support only for (FIFO registers) CAPABILITIES, FLAGS, and FENCE.
+    * This means that the guest has to test individually (in most cases
+    * using FIFO caps) for the presence of registers after this; the VMX
+    * can define "extended FIFO" to mean whatever it wants, and currently
+    * won't enable it unless there's room for that set and much more.
+    */
+
+   SVGA_FIFO_CAPABILITIES = 4,
+   SVGA_FIFO_FLAGS,
+   // Valid with SVGA_FIFO_CAP_FENCE:
+   SVGA_FIFO_FENCE,
+
+   /*
+    * Block 3a (optional extended registers): Additional registers for the
+    * extended FIFO, whose presence isn't actually implied by
+    * SVGA_CAP_EXTENDED_FIFO; these exist if SVGA_FIFO_MIN is high enough to
+    * leave room for them.
+    *
+    * These in block 3a, the VMX currently considers mandatory for the
+    * extended FIFO.
+    */
+
+   // Valid if exists (i.e. if extended FIFO enabled):
+   SVGA_FIFO_3D_HWVERSION,       /* See SVGA3dHardwareVersion in svga3d_reg.h */
+   // Valid with SVGA_FIFO_CAP_PITCHLOCK:
+   SVGA_FIFO_PITCHLOCK,
+
+   // Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3:
+   SVGA_FIFO_CURSOR_ON,          /* Cursor bypass 3 show/hide register */
+   SVGA_FIFO_CURSOR_X,           /* Cursor bypass 3 x register */
+   SVGA_FIFO_CURSOR_Y,           /* Cursor bypass 3 y register */
+   SVGA_FIFO_CURSOR_COUNT,       /* Incremented when any of the other 3 change */
+   SVGA_FIFO_CURSOR_LAST_UPDATED,/* Last time the host updated the cursor */
+
+   // Valid with SVGA_FIFO_CAP_RESERVE:
+   SVGA_FIFO_RESERVED,           /* Bytes past NEXT_CMD with real contents */
+
+   /*
+    * Valid with SVGA_FIFO_CAP_SCREEN_OBJECT:
+    *
+    * By default this is SVGA_ID_INVALID, to indicate that the cursor
+    * coordinates are specified relative to the virtual root. If this
+    * is set to a specific screen ID, cursor position is reinterpreted
+    * as a signed offset relative to that screen's origin. This is the
+    * only way to place the cursor on a non-rooted screen.
+    */
+   SVGA_FIFO_CURSOR_SCREEN_ID,
+
+   /*
+    * XXX: The gap here, up until SVGA_FIFO_3D_CAPS, can be used for new
+    * registers, but this must be done carefully and with judicious use of
+    * capability bits, since comparisons based on SVGA_FIFO_MIN aren't
+    * enough to tell you whether the register exists: we've shipped drivers
+    * and products that used SVGA_FIFO_3D_CAPS but didn't know about some of
+    * the earlier ones.  The actual order of introduction was:
+    * - PITCHLOCK
+    * - 3D_CAPS
+    * - CURSOR_* (cursor bypass 3)
+    * - RESERVED
+    * So, code that wants to know whether it can use any of the
+    * aforementioned registers, or anything else added after PITCHLOCK and
+    * before 3D_CAPS, needs to reason about something other than
+    * SVGA_FIFO_MIN.
+    */
+
+   /*
+    * 3D caps block space; valid with 3D hardware version >=
+    * SVGA3D_HWVERSION_WS6_B1.
+    */
+   SVGA_FIFO_3D_CAPS      = 32,
+   SVGA_FIFO_3D_CAPS_LAST = 32 + 255,
+
+   /*
+    * End of VMX's current definition of "extended-FIFO registers".
+    * Registers before here are always enabled/disabled as a block; either
+    * the extended FIFO is enabled and includes all preceding registers, or
+    * it's disabled entirely.
+    *
+    * Block 3b (truly optional extended registers): Additional registers for
+    * the extended FIFO, which the VMX already knows how to enable and
+    * disable with correct granularity.
+    *
+    * Registers after here exist if and only if the guest SVGA driver
+    * sets SVGA_FIFO_MIN high enough to leave room for them.
+    */
+
+   // Valid if register exists:
+   SVGA_FIFO_GUEST_3D_HWVERSION, /* Guest driver's 3D version */
+   SVGA_FIFO_FENCE_GOAL,         /* Matching target for SVGA_IRQFLAG_FENCE_GOAL */
+   SVGA_FIFO_BUSY,               /* See "FIFO Synchronization Registers" */
+
+   /*
+    * Always keep this last.  This defines the maximum number of
+    * registers we know about.  At power-on, this value is placed in
+    * the SVGA_REG_MEM_REGS register, and we expect the guest driver
+    * to allocate this much space in FIFO memory for registers.
+    */
+    SVGA_FIFO_NUM_REGS
+};
+
+
+/*
+ * Definition of registers included in extended FIFO support.
+ *
+ * The guest SVGA driver gets to allocate the FIFO between registers
+ * and data.  It must always allocate at least 4 registers, but old
+ * drivers stopped there.
+ *
+ * The VMX will enable extended FIFO support if and only if the guest
+ * left enough room for all registers defined as part of the mandatory
+ * set for the extended FIFO.
+ *
+ * Note that the guest drivers typically allocate the FIFO only at
+ * initialization time, not at mode switches, so it's likely that the
+ * number of FIFO registers won't change without a reboot.
+ *
+ * All registers less than this value are guaranteed to be present if
+ * svgaUser->fifo.extended is set. Any later registers must be tested
+ * individually for compatibility at each use (in the VMX).
+ *
+ * This value is used only by the VMX, so it can change without
+ * affecting driver compatibility; keep it that way?
+ */
+#define SVGA_FIFO_EXTENDED_MANDATORY_REGS  (SVGA_FIFO_3D_CAPS_LAST + 1)
+
+
+/*
+ * FIFO Synchronization Registers
+ *
+ *  This explains the relationship between the various FIFO
+ *  sync-related registers in IOSpace and in FIFO space.
+ *
+ *  SVGA_REG_SYNC --
+ *
+ *       The SYNC register can be used in two different ways by the guest:
+ *
+ *         1. If the guest wishes to fully sync (drain) the FIFO,
+ *            it will write once to SYNC then poll on the BUSY
+ *            register. The FIFO is sync'ed once BUSY is zero.
+ *
+ *         2. If the guest wants to asynchronously wake up the host,
+ *            it will write once to SYNC without polling on BUSY.
+ *            Ideally it will do this after some new commands have
+ *            been placed in the FIFO, and after reading a zero
+ *            from SVGA_FIFO_BUSY.
+ *
+ *       (1) is the original behaviour that SYNC was designed to
+ *       support.  Originally, a write to SYNC would implicitly
+ *       trigger a read from BUSY. This causes us to synchronously
+ *       process the FIFO.
+ *
+ *       This behaviour has since been changed so that writing SYNC
+ *       will *not* implicitly cause a read from BUSY. Instead, it
+ *       makes a channel call which asynchronously wakes up the MKS
+ *       thread.
+ *
+ *       New guests can use this new behaviour to implement (2)
+ *       efficiently. This lets guests get the host's attention
+ *       without waiting for the MKS to poll, which gives us much
+ *       better CPU utilization on SMP hosts and on UP hosts while
+ *       we're blocked on the host GPU.
+ *
+ *       Old guests shouldn't notice the behaviour change. SYNC was
+ *       never guaranteed to process the entire FIFO, since it was
+ *       bounded to a particular number of CPU cycles. Old guests will
+ *       still loop on the BUSY register until the FIFO is empty.
+ *
+ *       Writing to SYNC currently has the following side-effects:
+ *
+ *         - Sets SVGA_REG_BUSY to TRUE (in the monitor)
+ *         - Asynchronously wakes up the MKS thread for FIFO processing
+ *         - The value written to SYNC is recorded as a "reason", for
+ *           stats purposes.
+ *
+ *       If SVGA_FIFO_BUSY is available, drivers are advised to only
+ *       write to SYNC if SVGA_FIFO_BUSY is FALSE. Drivers should set
+ *       SVGA_FIFO_BUSY to TRUE after writing to SYNC. The MKS will
+ *       eventually set SVGA_FIFO_BUSY on its own, but this approach
+ *       lets the driver avoid sending multiple asynchronous wakeup
+ *       messages to the MKS thread.
+ *
+ *  SVGA_REG_BUSY --
+ *
+ *       This register is set to TRUE when SVGA_REG_SYNC is written,
+ *       and it reads as FALSE when the FIFO has been completely
+ *       drained.
+ *
+ *       Every read from this register causes us to synchronously
+ *       process FIFO commands. There is no guarantee as to how many
+ *       commands each read will process.
+ *
+ *       CPU time spent processing FIFO commands will be billed to
+ *       the guest.
+ *
+ *       New drivers should avoid using this register unless they
+ *       need to guarantee that the FIFO is completely drained. It
+ *       is overkill for performing a sync-to-fence. Older drivers
+ *       will use this register for any type of synchronization.
+ *
+ *  SVGA_FIFO_BUSY --
+ *
+ *       This register is a fast way for the guest driver to check
+ *       whether the FIFO is already being processed. It reads and
+ *       writes at normal RAM speeds, with no monitor intervention.
+ *
+ *       If this register reads as TRUE, the host is guaranteeing that
+ *       any new commands written into the FIFO will be noticed before
+ *       the MKS goes back to sleep.
+ *
+ *       If this register reads as FALSE, no such guarantee can be
+ *       made.
+ *
+ *       The guest should use this register to quickly determine
+ *       whether or not it needs to wake up the host. If the guest
+ *       just wrote a command or group of commands that it would like
+ *       the host to begin processing, it should:
+ *
+ *         1. Read SVGA_FIFO_BUSY. If it reads as TRUE, no further
+ *            action is necessary.
+ *
+ *         2. Write TRUE to SVGA_FIFO_BUSY. This informs future guest
+ *            code that we've already sent a SYNC to the host and we
+ *            don't need to send a duplicate.
+ *
+ *         3. Write a reason to SVGA_REG_SYNC. This will send an
+ *            asynchronous wakeup to the MKS thread.
+ */
+
+
+/*
+ * FIFO Capabilities
+ *
+ *      Fence -- Fence register and command are supported
+ *      Accel Front -- Front buffer only commands are supported
+ *      Pitch Lock -- Pitch lock register is supported
+ *      Video -- SVGA Video overlay units are supported
+ *      Escape -- Escape command is supported
+ *
+ * XXX: Add longer descriptions for each capability, including a list
+ *      of the new features that each capability provides.
+ *
+ * SVGA_FIFO_CAP_SCREEN_OBJECT --
+ *
+ *    Provides dynamic multi-screen rendering, for improved Unity and
+ *    multi-monitor modes. With Screen Object, the guest can
+ *    dynamically create and destroy 'screens', which can represent
+ *    Unity windows or virtual monitors. Screen Object also provides
+ *    strong guarantees that DMA operations happen only when
+ *    guest-initiated. Screen Object deprecates the BAR1 guest
+ *    framebuffer (GFB) and all commands that work only with the GFB.
+ *
+ *    New registers:
+ *       FIFO_CURSOR_SCREEN_ID, VIDEO_DATA_GMRID, VIDEO_DST_SCREEN_ID
+ *
+ *    New 2D commands:
+ *       DEFINE_SCREEN, DESTROY_SCREEN, DEFINE_GMRFB, BLIT_GMRFB_TO_SCREEN,
+ *       BLIT_SCREEN_TO_GMRFB, ANNOTATION_FILL, ANNOTATION_COPY
+ *
+ *    New 3D commands:
+ *       BLIT_SURFACE_TO_SCREEN
+ *
+ *    New guarantees:
+ *
+ *       - The host will not read or write guest memory, including the GFB,
+ *         except when explicitly initiated by a DMA command.
+ *
+ *       - All DMA, including legacy DMA like UPDATE and PRESENT_READBACK,
+ *         is guaranteed to complete before any subsequent FENCEs.
+ *
+ *       - All legacy commands which affect a Screen (UPDATE, PRESENT,
+ *         PRESENT_READBACK) as well as new Screen blit commands will
+ *         all behave consistently as blits, and memory will be read
+ *         or written in FIFO order.
+ *
+ *         For example, if you PRESENT from one SVGA3D surface to multiple
+ *         places on the screen, the data copied will always be from the
+ *         SVGA3D surface at the time the PRESENT was issued in the FIFO.
+ *         This was not necessarily true on devices without Screen Object.
+ *
+ *         This means that on devices that support Screen Object, the
+ *         PRESENT_READBACK command should not be necessary unless you
+ *         actually want to read back the results of 3D rendering into
+ *         system memory. (And for that, the BLIT_SCREEN_TO_GMRFB
+ *         command provides a strict superset of functionality.)
+ *
+ *       - When a screen is resized, either using Screen Object commands or
+ *         legacy multimon registers, its contents are preserved.
+ */
+
+#define SVGA_FIFO_CAP_NONE                  0
+#define SVGA_FIFO_CAP_FENCE             (1<<0)
+#define SVGA_FIFO_CAP_ACCELFRONT        (1<<1)
+#define SVGA_FIFO_CAP_PITCHLOCK         (1<<2)
+#define SVGA_FIFO_CAP_VIDEO             (1<<3)
+#define SVGA_FIFO_CAP_CURSOR_BYPASS_3   (1<<4)
+#define SVGA_FIFO_CAP_ESCAPE            (1<<5)
+#define SVGA_FIFO_CAP_RESERVE           (1<<6)
+#define SVGA_FIFO_CAP_SCREEN_OBJECT     (1<<7)
+
+
+/*
+ * FIFO Flags
+ *
+ *      Accel Front -- Driver should use front buffer only commands
+ */
+
+#define SVGA_FIFO_FLAG_NONE                 0
+#define SVGA_FIFO_FLAG_ACCELFRONT       (1<<0)
+#define SVGA_FIFO_FLAG_RESERVED        (1<<31) // Internal use only
+
+/*
+ * FIFO reservation sentinel value
+ */
+
+#define SVGA_FIFO_RESERVED_UNKNOWN      0xffffffff
+
+
+/*
+ * Video overlay support
+ */
+
+#define SVGA_NUM_OVERLAY_UNITS 32
+
+
+/*
+ * Video capabilities that the guest is currently using
+ */
+
+#define SVGA_VIDEO_FLAG_COLORKEY        0x0001
+
+
+/*
+ * Offsets for the video overlay registers
+ */
+
+enum {
+   SVGA_VIDEO_ENABLED = 0,
+   SVGA_VIDEO_FLAGS,
+   SVGA_VIDEO_DATA_OFFSET,
+   SVGA_VIDEO_FORMAT,
+   SVGA_VIDEO_COLORKEY,
+   SVGA_VIDEO_SIZE,          // Deprecated
+   SVGA_VIDEO_WIDTH,
+   SVGA_VIDEO_HEIGHT,
+   SVGA_VIDEO_SRC_X,
+   SVGA_VIDEO_SRC_Y,
+   SVGA_VIDEO_SRC_WIDTH,
+   SVGA_VIDEO_SRC_HEIGHT,
+   SVGA_VIDEO_DST_X,         // Signed int32
+   SVGA_VIDEO_DST_Y,         // Signed int32
+   SVGA_VIDEO_DST_WIDTH,
+   SVGA_VIDEO_DST_HEIGHT,
+   SVGA_VIDEO_PITCH_1,
+   SVGA_VIDEO_PITCH_2,
+   SVGA_VIDEO_PITCH_3,
+   SVGA_VIDEO_DATA_GMRID,    // Optional, defaults to SVGA_GMR_FRAMEBUFFER
+   SVGA_VIDEO_DST_SCREEN_ID, // Optional, defaults to virtual coords (SVGA_ID_INVALID)
+   SVGA_VIDEO_NUM_REGS
+};
+
+
+/*
+ * SVGA Overlay Units
+ *
+ *      width and height relate to the entire source video frame.
+ *      srcX, srcY, srcWidth and srcHeight represent subset of the source
+ *      video frame to be displayed.
+ */
+
+typedef struct SVGAOverlayUnit {
+   uint32 enabled;
+   uint32 flags;
+   uint32 dataOffset;
+   uint32 format;
+   uint32 colorKey;
+   uint32 size;
+   uint32 width;
+   uint32 height;
+   uint32 srcX;
+   uint32 srcY;
+   uint32 srcWidth;
+   uint32 srcHeight;
+   int32  dstX;
+   int32  dstY;
+   uint32 dstWidth;
+   uint32 dstHeight;
+   uint32 pitches[3];
+   uint32 dataGMRId;
+   uint32 dstScreenId;
+} SVGAOverlayUnit;
+
+
+/*
+ * SVGAScreenObject --
+ *
+ *    This is a new way to represent a guest's multi-monitor screen or
+ *    Unity window. Screen objects are only supported if the
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT capability bit is set.
+ *
+ *    If Screen Objects are supported, they can be used to fully
+ *    replace the functionality provided by the framebuffer registers
+ *    (SVGA_REG_WIDTH, HEIGHT, etc.) and by SVGA_CAP_DISPLAY_TOPOLOGY.
+ *
+ *    The screen object is a struct with guaranteed binary
+ *    compatibility. New flags can be added, and the struct may grow,
+ *    but existing fields must retain their meaning.
+ *
+ */
+
+#define SVGA_SCREEN_HAS_ROOT    (1 << 0)  // Screen is present in the virtual coord space
+#define SVGA_SCREEN_IS_PRIMARY  (1 << 1)  // Guest considers this screen to be 'primary'
+#define SVGA_SCREEN_FULLSCREEN_HINT (1 << 2)   // Guest is running a fullscreen app here
+
+typedef
+struct SVGAScreenObject {
+   uint32 structSize;   // sizeof(SVGAScreenObject)
+   uint32 id;
+   uint32 flags;
+   struct {
+      uint32 width;
+      uint32 height;
+   } size;
+   struct {
+      int32 x;
+      int32 y;
+   } root;              // Only used if SVGA_SCREEN_HAS_ROOT is set.
+} SVGAScreenObject;
+
+
+/*
+ *  Commands in the command FIFO:
+ *
+ *  Command IDs defined below are used for the traditional 2D FIFO
+ *  communication (not all commands are available for all versions of the
+ *  SVGA FIFO protocol).
+ *
+ *  Note the holes in the command ID numbers: These commands have been
+ *  deprecated, and the old IDs must not be reused.
+ *
+ *  Command IDs from 1000 to 1999 are reserved for use by the SVGA3D
+ *  protocol.
+ *
+ *  Each command's parameters are described by the comments and
+ *  structs below.
+ */
+
+typedef enum {
+   SVGA_CMD_INVALID_CMD           = 0,
+   SVGA_CMD_UPDATE                = 1,
+   SVGA_CMD_RECT_COPY             = 3,
+   SVGA_CMD_DEFINE_CURSOR         = 19,
+   SVGA_CMD_DEFINE_ALPHA_CURSOR   = 22,
+   SVGA_CMD_UPDATE_VERBOSE        = 25,
+   SVGA_CMD_FRONT_ROP_FILL        = 29,
+   SVGA_CMD_FENCE                 = 30,
+   SVGA_CMD_ESCAPE                = 33,
+   SVGA_CMD_DEFINE_SCREEN         = 34,
+   SVGA_CMD_DESTROY_SCREEN        = 35,
+   SVGA_CMD_DEFINE_GMRFB          = 36,
+   SVGA_CMD_BLIT_GMRFB_TO_SCREEN  = 37,
+   SVGA_CMD_BLIT_SCREEN_TO_GMRFB  = 38,
+   SVGA_CMD_ANNOTATION_FILL       = 39,
+   SVGA_CMD_ANNOTATION_COPY       = 40,
+   SVGA_CMD_MAX
+} SVGAFifoCmdId;
+
+#define SVGA_CMD_MAX_ARGS           64
+
+
+/*
+ * SVGA_CMD_UPDATE --
+ *
+ *    This is a DMA transfer which copies from the Guest Framebuffer
+ *    (GFB) at BAR1 + SVGA_REG_FB_OFFSET to any screens which
+ *    intersect with the provided virtual rectangle.
+ *
+ *    This command does not support using arbitrary guest memory as a
+ *    data source- it only works with the pre-defined GFB memory.
+ *    This command also does not support signed virtual coordinates.
+ *    If you have defined screens (using SVGA_CMD_DEFINE_SCREEN) with
+ *    negative root x/y coordinates, the negative portion of those
+ *    screens will not be reachable by this command.
+ *
+ *    This command is not necessary when using framebuffer
+ *    traces. Traces are automatically enabled if the SVGA FIFO is
+ *    disabled, and you may explicitly enable/disable traces using
+ *    SVGA_REG_TRACES. With traces enabled, any write to the GFB will
+ *    automatically act as if a subsequent SVGA_CMD_UPDATE was issued.
+ *
+ *    Traces and SVGA_CMD_UPDATE are the only supported ways to render
+ *    pseudocolor screen updates. The newer Screen Object commands
+ *    only support true color formats.
+ *
+ * Availability:
+ *    Always available.
+ */
+
+typedef
+struct {
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+} SVGAFifoCmdUpdate;
+
+
+/*
+ * SVGA_CMD_RECT_COPY --
+ *
+ *    Perform a rectangular DMA transfer from one area of the GFB to
+ *    another, and copy the result to any screens which intersect it.
+ *
+ * Availability:
+ *    SVGA_CAP_RECT_COPY
+ */
+
+typedef
+struct {
+   uint32 srcX;
+   uint32 srcY;
+   uint32 destX;
+   uint32 destY;
+   uint32 width;
+   uint32 height;
+} SVGAFifoCmdRectCopy;
+
+
+/*
+ * SVGA_CMD_DEFINE_CURSOR --
+ *
+ *    Provide a new cursor image, as an AND/XOR mask.
+ *
+ *    The recommended way to position the cursor overlay is by using
+ *    the SVGA_FIFO_CURSOR_* registers, supported by the
+ *    SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ *    SVGA_CAP_CURSOR
+ */
+
+typedef
+struct {
+   uint32 id;             // Reserved, must be zero.
+   uint32 hotspotX;
+   uint32 hotspotY;
+   uint32 width;
+   uint32 height;
+   uint32 andMaskDepth;   // Value must be 1 or equal to BITS_PER_PIXEL
+   uint32 xorMaskDepth;   // Value must be 1 or equal to BITS_PER_PIXEL
+   /*
+    * Followed by scanline data for AND mask, then XOR mask.
+    * Each scanline is padded to a 32-bit boundary.
+   */
+} SVGAFifoCmdDefineCursor;
+
+
+/*
+ * SVGA_CMD_DEFINE_ALPHA_CURSOR --
+ *
+ *    Provide a new cursor image, in 32-bit BGRA format.
+ *
+ *    The recommended way to position the cursor overlay is by using
+ *    the SVGA_FIFO_CURSOR_* registers, supported by the
+ *    SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ *    SVGA_CAP_ALPHA_CURSOR
+ */
+
+typedef
+struct {
+   uint32 id;             // Reserved, must be zero.
+   uint32 hotspotX;
+   uint32 hotspotY;
+   uint32 width;
+   uint32 height;
+   /* Followed by scanline data */
+} SVGAFifoCmdDefineAlphaCursor;
+
+
+/*
+ * SVGA_CMD_UPDATE_VERBOSE --
+ *
+ *    Just like SVGA_CMD_UPDATE, but also provide a per-rectangle
+ *    'reason' value, an opaque cookie which is used by internal
+ *    debugging tools. Third party drivers should not use this
+ *    command.
+ *
+ * Availability:
+ *    SVGA_CAP_EXTENDED_FIFO
+ */
+
+typedef
+struct {
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+   uint32 reason;
+} SVGAFifoCmdUpdateVerbose;
+
+
+/*
+ * SVGA_CMD_FRONT_ROP_FILL --
+ *
+ *    This is a hint which tells the SVGA device that the driver has
+ *    just filled a rectangular region of the GFB with a solid
+ *    color. Instead of reading these pixels from the GFB, the device
+ *    can assume that they all equal 'color'. This is primarily used
+ *    for remote desktop protocols.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_ACCELFRONT
+ */
+
+#define  SVGA_ROP_COPY                    0x03
+
+typedef
+struct {
+   uint32 color;     // In the same format as the GFB
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+   uint32 rop;       // Must be SVGA_ROP_COPY
+} SVGAFifoCmdFrontRopFill;
+
+
+/*
+ * SVGA_CMD_FENCE --
+ *
+ *    Insert a synchronization fence.  When the SVGA device reaches
+ *    this command, it will copy the 'fence' value into the
+ *    SVGA_FIFO_FENCE register. It will also compare the fence against
+ *    SVGA_FIFO_FENCE_GOAL. If the fence matches the goal and the
+ *    SVGA_IRQFLAG_FENCE_GOAL interrupt is enabled, the device will
+ *    raise this interrupt.
+ *
+ * Availability:
+ *    SVGA_FIFO_FENCE for this command,
+ *    SVGA_CAP_IRQMASK for SVGA_FIFO_FENCE_GOAL.
+ */
+
+typedef
+struct {
+   uint32 fence;
+} SVGAFifoCmdFence;
+
+
+/*
+ * SVGA_CMD_ESCAPE --
+ *
+ *    Send an extended or vendor-specific variable length command.
+ *    This is used for video overlay, third party plugins, and
+ *    internal debugging tools. See svga_escape.h
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_ESCAPE
+ */
+
+typedef
+struct {
+   uint32 nsid;
+   uint32 size;
+   /* followed by 'size' bytes of data */
+} SVGAFifoCmdEscape;
+
+
+/*
+ * SVGA_CMD_DEFINE_SCREEN --
+ *
+ *    Define or redefine an SVGAScreenObject. See the description of
+ *    SVGAScreenObject above.  The video driver is responsible for
+ *    generating new screen IDs. They should be small positive
+ *    integers. The virtual device will have an implementation
+ *    specific upper limit on the number of screen IDs
+ *    supported. Drivers are responsible for recycling IDs. The first
+ *    valid ID is zero.
+ *
+ *    - Interaction with other registers:
+ *
+ *    For backwards compatibility, when the GFB mode registers (WIDTH,
+ *    HEIGHT, PITCHLOCK, BITS_PER_PIXEL) are modified, the SVGA device
+ *    deletes all screens other than screen #0, and redefines screen
+ *    #0 according to the specified mode. Drivers that use
+ *    SVGA_CMD_DEFINE_SCREEN should destroy or redefine screen #0.
+ *
+ *    If you use screen objects, do not use the legacy multi-mon
+ *    registers (SVGA_REG_NUM_GUEST_DISPLAYS, SVGA_REG_DISPLAY_*).
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGAScreenObject screen;   // Variable-length according to version
+} SVGAFifoCmdDefineScreen;
+
+
+/*
+ * SVGA_CMD_DESTROY_SCREEN --
+ *
+ *    Destroy an SVGAScreenObject. Its ID is immediately available for
+ *    re-use.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   uint32 screenId;
+} SVGAFifoCmdDestroyScreen;
+
+
+/*
+ * SVGA_CMD_DEFINE_GMRFB --
+ *
+ *    This command sets a piece of SVGA device state called the
+ *    Guest Memory Region Framebuffer, or GMRFB. The GMRFB is a
+ *    piece of light-weight state which identifies the location and
+ *    format of an image in guest memory or in BAR1. The GMRFB has
+ *    an arbitrary size, and it doesn't need to match the geometry
+ *    of the GFB or any screen object.
+ *
+ *    The GMRFB can be redefined as often as you like. You could
+ *    always use the same GMRFB, you could redefine it before
+ *    rendering from a different guest screen, or you could even
+ *    redefine it before every blit.
+ *
+ *    There are multiple ways to use this command. The simplest way is
+ *    to use it to move the framebuffer either to elsewhere in the GFB
+ *    (BAR1) memory region, or to a user-defined GMR. This lets a
+ *    driver use a framebuffer allocated entirely out of normal system
+ *    memory, which we encourage.
+ *
+ *    Another way to use this command is to set up a ring buffer of
+ *    updates in GFB memory. If a driver wants to ensure that no
+ *    frames are skipped by the SVGA device, it is important that the
+ *    driver not modify the source data for a blit until the device is
+ *    done processing the command. One efficient way to accomplish
+ *    this is to use a ring of small DMA buffers. Each buffer is used
+ *    for one blit, then we move on to the next buffer in the
+ *    ring. The FENCE mechanism is used to protect each buffer from
+ *    re-use until the device is finished with that buffer's
+ *    corresponding blit.
+ *
+ *    This command does not affect the meaning of SVGA_CMD_UPDATE.
+ *    UPDATEs always occur from the legacy GFB memory area. This
+ *    command has no support for pseudocolor GMRFBs. Currently only
+ *    true-color 15, 16, and 24-bit depths are supported. Future
+ *    devices may expose capabilities for additional framebuffer
+ *    formats.
+ *
+ *    The default GMRFB value is undefined. Drivers must always send
+ *    this command at least once before performing any blit from the
+ *    GMRFB.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGAGuestPtr        ptr;
+   uint32              bytesPerLine;
+   SVGAGMRImageFormat  format;
+} SVGAFifoCmdDefineGMRFB;
+
+
+/*
+ * SVGA_CMD_BLIT_GMRFB_TO_SCREEN --
+ *
+ *    This is a guest-to-host blit. It performs a DMA operation to
+ *    copy a rectangular region of pixels from the current GMRFB to
+ *    one or more Screen Objects.
+ *
+ *    The destination coordinate may be specified relative to a
+ *    screen's origin (if a screen ID is specified) or relative to the
+ *    virtual coordinate system's origin (if the screen ID is
+ *    SVGA_ID_INVALID). The actual destination may span zero or more
+ *    screens, in the case of a virtual destination rect or a rect
+ *    which extends off the edge of the specified screen.
+ *
+ *    This command writes to the screen's "base layer": the underlying
+ *    framebuffer which exists below any cursor or video overlays. No
+ *    action is necessary to explicitly hide or update any overlays
+ *    which exist on top of the updated region.
+ *
+ *    The SVGA device is guaranteed to finish reading from the GMRFB
+ *    by the time any subsequent FENCE commands are reached.
+ *
+ *    This command consumes an annotation. See the
+ *    SVGA_CMD_ANNOTATION_* commands for details.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGASignedPoint  srcOrigin;
+   SVGASignedRect   destRect;
+   uint32           destScreenId;
+} SVGAFifoCmdBlitGMRFBToScreen;
+
+
+/*
+ * SVGA_CMD_BLIT_SCREEN_TO_GMRFB --
+ *
+ *    This is a host-to-guest blit. It performs a DMA operation to
+ *    copy a rectangular region of pixels from a single Screen Object
+ *    back to the current GMRFB.
+ *
+ *    Usage note: This command should be used rarely. It will
+ *    typically be inefficient, but it is necessary for some types of
+ *    synchronization between 3D (GPU) and 2D (CPU) rendering into
+ *    overlapping areas of a screen.
+ *
+ *    The source coordinate is specified relative to a screen's
+ *    origin. The provided screen ID must be valid. If any parameters
+ *    are invalid, the resulting pixel values are undefined.
+ *
+ *    This command reads the screen's "base layer". Overlays like
+ *    video and cursor are not included, but any data which was sent
+ *    using a blit-to-screen primitive will be available, no matter
+ *    whether the data's original source was the GMRFB or the 3D
+ *    acceleration hardware.
+ *
+ *    Note that our guest-to-host blits and host-to-guest blits aren't
+ *    symmetric in their current implementation. While the parameters
+ *    are identical, host-to-guest blits are a lot less featureful.
+ *    They do not support clipping: If the source parameters don't
+ *    fully fit within a screen, the blit fails. They must originate
+ *    from exactly one screen. Virtual coordinates are not directly
+ *    supported.
+ *
+ *    Host-to-guest blits do support the same set of GMRFB formats
+ *    offered by guest-to-host blits.
+ *
+ *    The SVGA device is guaranteed to finish writing to the GMRFB by
+ *    the time any subsequent FENCE commands are reached.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGASignedPoint  destOrigin;
+   SVGASignedRect   srcRect;
+   uint32           srcScreenId;
+} SVGAFifoCmdBlitScreenToGMRFB;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_FILL --
+ *
+ *    This is a blit annotation. This command stores a small piece of
+ *    device state which is consumed by the next blit-to-screen
+ *    command. The state is only cleared by commands which are
+ *    specifically documented as consuming an annotation. Other
+ *    commands (such as ESCAPEs for debugging) may intervene between
+ *    the annotation and its associated blit.
+ *
+ *    This annotation is a promise about the contents of the next
+ *    blit: The video driver is guaranteeing that all pixels in that
+ *    blit will have the same value, specified here as a color in
+ *    SVGAColorBGRX format.
+ *
+ *    The SVGA device can still render the blit correctly even if it
+ *    ignores this annotation, but the annotation may allow it to
+ *    perform the blit more efficiently, for example by ignoring the
+ *    source data and performing a fill in hardware.
+ *
+ *    This annotation is most important for performance when the
+ *    user's display is being remoted over a network connection.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGAColorBGRX  color;
+} SVGAFifoCmdAnnotationFill;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_COPY --
+ *
+ *    This is a blit annotation. See SVGA_CMD_ANNOTATION_FILL for more
+ *    information about annotations.
+ *
+ *    This annotation is a promise about the contents of the next
+ *    blit: The video driver is guaranteeing that all pixels in that
+ *    blit will have the same value as those which already exist at an
+ *    identically-sized region on the same or a different screen.
+ *
+ *    Note that the source pixels for the COPY in this annotation are
+ *    sampled before applying the anqnotation's associated blit. They
+ *    are allowed to overlap with the blit's destination pixels.
+ *
+ *    The copy source rectangle is specified the same way as the blit
+ *    destination: it can be a rectangle which spans zero or more
+ *    screens, specified relative to either a screen or to the virtual
+ *    coordinate system's origin. If the source rectangle includes
+ *    pixels which are not from exactly one screen, the results are
+ *    undefined.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGASignedPoint  srcOrigin;
+   uint32           srcScreenId;
+} SVGAFifoCmdAnnotationCopy;
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/svga_types.h b/drivers/gpu/drm/vmwgfx/svga_types.h
new file mode 100644 (file)
index 0000000..55836de
--- /dev/null
@@ -0,0 +1,45 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * Silly typedefs for the svga headers. Currently the headers are shared
+ * between all components that talk to svga. And as such the headers are
+ * are in a completely different style and use weird defines.
+ *
+ * This file lets all the ugly be prefixed with svga*.
+ */
+
+#ifndef _SVGA_TYPES_H_
+#define _SVGA_TYPES_H_
+
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint8_t uint8;
+typedef int32_t int32;
+typedef bool Bool;
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
new file mode 100644 (file)
index 0000000..d6f2d2b
--- /dev/null
@@ -0,0 +1,229 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+
+static uint32_t vram_placement_flags = TTM_PL_FLAG_VRAM |
+       TTM_PL_FLAG_CACHED;
+
+static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
+       TTM_PL_FLAG_CACHED |
+       TTM_PL_FLAG_NO_EVICT;
+
+static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
+       TTM_PL_FLAG_CACHED;
+
+struct ttm_placement vmw_vram_placement = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .num_placement = 1,
+       .placement = &vram_placement_flags,
+       .num_busy_placement = 1,
+       .busy_placement = &vram_placement_flags
+};
+
+struct ttm_placement vmw_vram_ne_placement = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .num_placement = 1,
+       .placement = &vram_ne_placement_flags,
+       .num_busy_placement = 1,
+       .busy_placement = &vram_ne_placement_flags
+};
+
+struct ttm_placement vmw_sys_placement = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .num_placement = 1,
+       .placement = &sys_placement_flags,
+       .num_busy_placement = 1,
+       .busy_placement = &sys_placement_flags
+};
+
+struct vmw_ttm_backend {
+       struct ttm_backend backend;
+};
+
+static int vmw_ttm_populate(struct ttm_backend *backend,
+                           unsigned long num_pages, struct page **pages,
+                           struct page *dummy_read_page)
+{
+       return 0;
+}
+
+static int vmw_ttm_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
+{
+       return 0;
+}
+
+static int vmw_ttm_unbind(struct ttm_backend *backend)
+{
+       return 0;
+}
+
+static void vmw_ttm_clear(struct ttm_backend *backend)
+{
+}
+
+static void vmw_ttm_destroy(struct ttm_backend *backend)
+{
+       struct vmw_ttm_backend *vmw_be =
+           container_of(backend, struct vmw_ttm_backend, backend);
+
+       kfree(vmw_be);
+}
+
+static struct ttm_backend_func vmw_ttm_func = {
+       .populate = vmw_ttm_populate,
+       .clear = vmw_ttm_clear,
+       .bind = vmw_ttm_bind,
+       .unbind = vmw_ttm_unbind,
+       .destroy = vmw_ttm_destroy,
+};
+
+struct ttm_backend *vmw_ttm_backend_init(struct ttm_bo_device *bdev)
+{
+       struct vmw_ttm_backend *vmw_be;
+
+       vmw_be = kmalloc(sizeof(*vmw_be), GFP_KERNEL);
+       if (!vmw_be)
+               return NULL;
+
+       vmw_be->backend.func = &vmw_ttm_func;
+
+       return &vmw_be->backend;
+}
+
+int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
+{
+       return 0;
+}
+
+int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+                     struct ttm_mem_type_manager *man)
+{
+       struct vmw_private *dev_priv =
+           container_of(bdev, struct vmw_private, bdev);
+
+       switch (type) {
+       case TTM_PL_SYSTEM:
+               /* System memory */
+
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case TTM_PL_VRAM:
+               /* "On-card" video ram */
+               man->gpu_offset = 0;
+               man->io_offset = dev_priv->vram_start;
+               man->io_size = dev_priv->vram_size;
+               man->flags = TTM_MEMTYPE_FLAG_FIXED |
+                   TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->io_addr = NULL;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_WC;
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+void vmw_evict_flags(struct ttm_buffer_object *bo,
+                    struct ttm_placement *placement)
+{
+       *placement = vmw_sys_placement;
+}
+
+/**
+ * FIXME: Proper access checks on buffers.
+ */
+
+static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+       return 0;
+}
+
+/**
+ * FIXME: We're using the old vmware polling method to sync.
+ * Do this with fences instead.
+ */
+
+static void *vmw_sync_obj_ref(void *sync_obj)
+{
+       return sync_obj;
+}
+
+static void vmw_sync_obj_unref(void **sync_obj)
+{
+       *sync_obj = NULL;
+}
+
+static int vmw_sync_obj_flush(void *sync_obj, void *sync_arg)
+{
+       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
+
+       mutex_lock(&dev_priv->hw_mutex);
+       vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
+       mutex_unlock(&dev_priv->hw_mutex);
+       return 0;
+}
+
+static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg)
+{
+       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
+       uint32_t sequence = (unsigned long) sync_obj;
+
+       return vmw_fence_signaled(dev_priv, sequence);
+}
+
+static int vmw_sync_obj_wait(void *sync_obj, void *sync_arg,
+                            bool lazy, bool interruptible)
+{
+       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
+       uint32_t sequence = (unsigned long) sync_obj;
+
+       return vmw_wait_fence(dev_priv, false, sequence, false, 3*HZ);
+}
+
+struct ttm_bo_driver vmw_bo_driver = {
+       .create_ttm_backend_entry = vmw_ttm_backend_init,
+       .invalidate_caches = vmw_invalidate_caches,
+       .init_mem_type = vmw_init_mem_type,
+       .evict_flags = vmw_evict_flags,
+       .move = NULL,
+       .verify_access = vmw_verify_access,
+       .sync_obj_signaled = vmw_sync_obj_signaled,
+       .sync_obj_wait = vmw_sync_obj_wait,
+       .sync_obj_flush = vmw_sync_obj_flush,
+       .sync_obj_unref = vmw_sync_obj_unref,
+       .sync_obj_ref = vmw_sync_obj_ref
+};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
new file mode 100644 (file)
index 0000000..7b48bb3
--- /dev/null
@@ -0,0 +1,735 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_object.h"
+#include "ttm/ttm_module.h"
+
+#define VMWGFX_DRIVER_NAME "vmwgfx"
+#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
+#define VMWGFX_CHIP_SVGAII 0
+#define VMW_FB_RESERVATION 0
+
+/**
+ * Fully encoded drm commands. Might move to vmw_drm.h
+ */
+
+#define DRM_IOCTL_VMW_GET_PARAM                                        \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GET_PARAM,          \
+                struct drm_vmw_getparam_arg)
+#define DRM_IOCTL_VMW_ALLOC_DMABUF                             \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_ALLOC_DMABUF,       \
+               union drm_vmw_alloc_dmabuf_arg)
+#define DRM_IOCTL_VMW_UNREF_DMABUF                             \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_DMABUF,        \
+               struct drm_vmw_unref_dmabuf_arg)
+#define DRM_IOCTL_VMW_CURSOR_BYPASS                            \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_CURSOR_BYPASS,       \
+                struct drm_vmw_cursor_bypass_arg)
+
+#define DRM_IOCTL_VMW_CONTROL_STREAM                           \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_CONTROL_STREAM,      \
+                struct drm_vmw_control_stream_arg)
+#define DRM_IOCTL_VMW_CLAIM_STREAM                             \
+       DRM_IOR(DRM_COMMAND_BASE + DRM_VMW_CLAIM_STREAM,        \
+                struct drm_vmw_stream_arg)
+#define DRM_IOCTL_VMW_UNREF_STREAM                             \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_STREAM,        \
+                struct drm_vmw_stream_arg)
+
+#define DRM_IOCTL_VMW_CREATE_CONTEXT                           \
+       DRM_IOR(DRM_COMMAND_BASE + DRM_VMW_CREATE_CONTEXT,      \
+               struct drm_vmw_context_arg)
+#define DRM_IOCTL_VMW_UNREF_CONTEXT                            \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_CONTEXT,       \
+               struct drm_vmw_context_arg)
+#define DRM_IOCTL_VMW_CREATE_SURFACE                           \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_SURFACE,     \
+                union drm_vmw_surface_create_arg)
+#define DRM_IOCTL_VMW_UNREF_SURFACE                            \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_SURFACE,       \
+                struct drm_vmw_surface_arg)
+#define DRM_IOCTL_VMW_REF_SURFACE                              \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_REF_SURFACE,        \
+                union drm_vmw_surface_reference_arg)
+#define DRM_IOCTL_VMW_EXECBUF                                  \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF,             \
+               struct drm_vmw_execbuf_arg)
+#define DRM_IOCTL_VMW_FIFO_DEBUG                               \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FIFO_DEBUG,         \
+                struct drm_vmw_fifo_debug_arg)
+#define DRM_IOCTL_VMW_FENCE_WAIT                               \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT,         \
+                struct drm_vmw_fence_wait_arg)
+
+
+/**
+ * The core DRM version of this macro doesn't account for
+ * DRM_COMMAND_BASE.
+ */
+
+#define VMW_IOCTL_DEF(ioctl, func, flags) \
+       [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func}
+
+/**
+ * Ioctl definitions.
+ */
+
+static struct drm_ioctl_desc vmw_ioctls[] = {
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl, 0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS,
+                     vmw_kms_cursor_bypass_ioctl, 0),
+
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_CONTROL_STREAM, vmw_overlay_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl,
+                     0),
+
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_CONTEXT, vmw_context_define_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_SURFACE, vmw_surface_define_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_REF_SURFACE, vmw_surface_reference_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_EXECBUF, vmw_execbuf_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl,
+                     0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
+                     0)
+};
+
+static struct pci_device_id vmw_pci_id_list[] = {
+       {0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII},
+       {0, 0, 0}
+};
+
+static char *vmw_devname = "vmwgfx";
+
+static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
+static void vmw_master_init(struct vmw_master *);
+
+static void vmw_print_capabilities(uint32_t capabilities)
+{
+       DRM_INFO("Capabilities:\n");
+       if (capabilities & SVGA_CAP_RECT_COPY)
+               DRM_INFO("  Rect copy.\n");
+       if (capabilities & SVGA_CAP_CURSOR)
+               DRM_INFO("  Cursor.\n");
+       if (capabilities & SVGA_CAP_CURSOR_BYPASS)
+               DRM_INFO("  Cursor bypass.\n");
+       if (capabilities & SVGA_CAP_CURSOR_BYPASS_2)
+               DRM_INFO("  Cursor bypass 2.\n");
+       if (capabilities & SVGA_CAP_8BIT_EMULATION)
+               DRM_INFO("  8bit emulation.\n");
+       if (capabilities & SVGA_CAP_ALPHA_CURSOR)
+               DRM_INFO("  Alpha cursor.\n");
+       if (capabilities & SVGA_CAP_3D)
+               DRM_INFO("  3D.\n");
+       if (capabilities & SVGA_CAP_EXTENDED_FIFO)
+               DRM_INFO("  Extended Fifo.\n");
+       if (capabilities & SVGA_CAP_MULTIMON)
+               DRM_INFO("  Multimon.\n");
+       if (capabilities & SVGA_CAP_PITCHLOCK)
+               DRM_INFO("  Pitchlock.\n");
+       if (capabilities & SVGA_CAP_IRQMASK)
+               DRM_INFO("  Irq mask.\n");
+       if (capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)
+               DRM_INFO("  Display Topology.\n");
+       if (capabilities & SVGA_CAP_GMR)
+               DRM_INFO("  GMR.\n");
+       if (capabilities & SVGA_CAP_TRACES)
+               DRM_INFO("  Traces.\n");
+}
+
+static int vmw_request_device(struct vmw_private *dev_priv)
+{
+       int ret;
+
+       vmw_kms_save_vga(dev_priv);
+
+       ret = vmw_fifo_init(dev_priv, &dev_priv->fifo);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Unable to initialize FIFO.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void vmw_release_device(struct vmw_private *dev_priv)
+{
+       vmw_fifo_release(dev_priv, &dev_priv->fifo);
+       vmw_kms_restore_vga(dev_priv);
+}
+
+
+static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
+{
+       struct vmw_private *dev_priv;
+       int ret;
+
+       dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
+       if (unlikely(dev_priv == NULL)) {
+               DRM_ERROR("Failed allocating a device private struct.\n");
+               return -ENOMEM;
+       }
+       memset(dev_priv, 0, sizeof(*dev_priv));
+
+       dev_priv->dev = dev;
+       dev_priv->vmw_chipset = chipset;
+       mutex_init(&dev_priv->hw_mutex);
+       mutex_init(&dev_priv->cmdbuf_mutex);
+       rwlock_init(&dev_priv->resource_lock);
+       idr_init(&dev_priv->context_idr);
+       idr_init(&dev_priv->surface_idr);
+       idr_init(&dev_priv->stream_idr);
+       ida_init(&dev_priv->gmr_ida);
+       mutex_init(&dev_priv->init_mutex);
+       init_waitqueue_head(&dev_priv->fence_queue);
+       init_waitqueue_head(&dev_priv->fifo_queue);
+       atomic_set(&dev_priv->fence_queue_waiters, 0);
+       atomic_set(&dev_priv->fifo_queue_waiters, 0);
+       INIT_LIST_HEAD(&dev_priv->gmr_lru);
+
+       dev_priv->io_start = pci_resource_start(dev->pdev, 0);
+       dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
+       dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
+
+       mutex_lock(&dev_priv->hw_mutex);
+       dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
+
+       if (dev_priv->capabilities & SVGA_CAP_GMR) {
+               dev_priv->max_gmr_descriptors =
+                       vmw_read(dev_priv,
+                                SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH);
+               dev_priv->max_gmr_ids =
+                       vmw_read(dev_priv, SVGA_REG_GMR_MAX_IDS);
+       }
+
+       dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE);
+       dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
+       dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH);
+       dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT);
+
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       vmw_print_capabilities(dev_priv->capabilities);
+
+       if (dev_priv->capabilities & SVGA_CAP_GMR) {
+               DRM_INFO("Max GMR ids is %u\n",
+                        (unsigned)dev_priv->max_gmr_ids);
+               DRM_INFO("Max GMR descriptors is %u\n",
+                        (unsigned)dev_priv->max_gmr_descriptors);
+       }
+       DRM_INFO("VRAM at 0x%08x size is %u kiB\n",
+                dev_priv->vram_start, dev_priv->vram_size / 1024);
+       DRM_INFO("MMIO at 0x%08x size is %u kiB\n",
+                dev_priv->mmio_start, dev_priv->mmio_size / 1024);
+
+       ret = vmw_ttm_global_init(dev_priv);
+       if (unlikely(ret != 0))
+               goto out_err0;
+
+
+       vmw_master_init(&dev_priv->fbdev_master);
+       ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+       dev_priv->active_master = &dev_priv->fbdev_master;
+
+
+       ret = ttm_bo_device_init(&dev_priv->bdev,
+                                dev_priv->bo_global_ref.ref.object,
+                                &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET,
+                                false);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed initializing TTM buffer object driver.\n");
+               goto out_err1;
+       }
+
+       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
+                            (dev_priv->vram_size >> PAGE_SHIFT));
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed initializing memory manager for VRAM.\n");
+               goto out_err2;
+       }
+
+       dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
+                                          dev_priv->mmio_size, DRM_MTRR_WC);
+
+       dev_priv->mmio_virt = ioremap_wc(dev_priv->mmio_start,
+                                        dev_priv->mmio_size);
+
+       if (unlikely(dev_priv->mmio_virt == NULL)) {
+               ret = -ENOMEM;
+               DRM_ERROR("Failed mapping MMIO.\n");
+               goto out_err3;
+       }
+
+       dev_priv->tdev = ttm_object_device_init
+           (dev_priv->mem_global_ref.object, 12);
+
+       if (unlikely(dev_priv->tdev == NULL)) {
+               DRM_ERROR("Unable to initialize TTM object management.\n");
+               ret = -ENOMEM;
+               goto out_err4;
+       }
+
+       dev->dev_private = dev_priv;
+
+       if (!dev->devname)
+               dev->devname = vmw_devname;
+
+       if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
+               ret = drm_irq_install(dev);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Failed installing irq: %d\n", ret);
+                       goto out_no_irq;
+               }
+       }
+
+       ret = pci_request_regions(dev->pdev, "vmwgfx probe");
+       dev_priv->stealth = (ret != 0);
+       if (dev_priv->stealth) {
+               /**
+                * Request at least the mmio PCI resource.
+                */
+
+               DRM_INFO("It appears like vesafb is loaded. "
+                        "Ignore above error if any. Entering stealth mode.\n");
+               ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe");
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Failed reserving the SVGA MMIO resource.\n");
+                       goto out_no_device;
+               }
+               vmw_kms_init(dev_priv);
+               vmw_overlay_init(dev_priv);
+       } else {
+               ret = vmw_request_device(dev_priv);
+               if (unlikely(ret != 0))
+                       goto out_no_device;
+               vmw_kms_init(dev_priv);
+               vmw_overlay_init(dev_priv);
+               vmw_fb_init(dev_priv);
+       }
+
+       return 0;
+
+out_no_device:
+       if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
+               drm_irq_uninstall(dev_priv->dev);
+       if (dev->devname == vmw_devname)
+               dev->devname = NULL;
+out_no_irq:
+       ttm_object_device_release(&dev_priv->tdev);
+out_err4:
+       iounmap(dev_priv->mmio_virt);
+out_err3:
+       drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
+                    dev_priv->mmio_size, DRM_MTRR_WC);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+out_err2:
+       (void)ttm_bo_device_release(&dev_priv->bdev);
+out_err1:
+       vmw_ttm_global_release(dev_priv);
+out_err0:
+       ida_destroy(&dev_priv->gmr_ida);
+       idr_destroy(&dev_priv->surface_idr);
+       idr_destroy(&dev_priv->context_idr);
+       idr_destroy(&dev_priv->stream_idr);
+       kfree(dev_priv);
+       return ret;
+}
+
+static int vmw_driver_unload(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n");
+
+       if (!dev_priv->stealth) {
+               vmw_fb_close(dev_priv);
+               vmw_kms_close(dev_priv);
+               vmw_overlay_close(dev_priv);
+               vmw_release_device(dev_priv);
+               pci_release_regions(dev->pdev);
+       } else {
+               vmw_kms_close(dev_priv);
+               vmw_overlay_close(dev_priv);
+               pci_release_region(dev->pdev, 2);
+       }
+       if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
+               drm_irq_uninstall(dev_priv->dev);
+       if (dev->devname == vmw_devname)
+               dev->devname = NULL;
+       ttm_object_device_release(&dev_priv->tdev);
+       iounmap(dev_priv->mmio_virt);
+       drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
+                    dev_priv->mmio_size, DRM_MTRR_WC);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+       (void)ttm_bo_device_release(&dev_priv->bdev);
+       vmw_ttm_global_release(dev_priv);
+       ida_destroy(&dev_priv->gmr_ida);
+       idr_destroy(&dev_priv->surface_idr);
+       idr_destroy(&dev_priv->context_idr);
+       idr_destroy(&dev_priv->stream_idr);
+
+       kfree(dev_priv);
+
+       return 0;
+}
+
+static void vmw_postclose(struct drm_device *dev,
+                        struct drm_file *file_priv)
+{
+       struct vmw_fpriv *vmw_fp;
+
+       vmw_fp = vmw_fpriv(file_priv);
+       ttm_object_file_release(&vmw_fp->tfile);
+       if (vmw_fp->locked_master)
+               drm_master_put(&vmw_fp->locked_master);
+       kfree(vmw_fp);
+}
+
+static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_fpriv *vmw_fp;
+       int ret = -ENOMEM;
+
+       vmw_fp = kzalloc(sizeof(*vmw_fp), GFP_KERNEL);
+       if (unlikely(vmw_fp == NULL))
+               return ret;
+
+       vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
+       if (unlikely(vmw_fp->tfile == NULL))
+               goto out_no_tfile;
+
+       file_priv->driver_priv = vmw_fp;
+
+       if (unlikely(dev_priv->bdev.dev_mapping == NULL))
+               dev_priv->bdev.dev_mapping =
+                       file_priv->filp->f_path.dentry->d_inode->i_mapping;
+
+       return 0;
+
+out_no_tfile:
+       kfree(vmw_fp);
+       return ret;
+}
+
+static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+{
+       struct drm_file *file_priv = filp->private_data;
+       struct drm_device *dev = file_priv->minor->dev;
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       long ret;
+
+       /*
+        * The driver private ioctls and TTM ioctls should be
+        * thread-safe.
+        */
+
+       if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
+           && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
+               struct drm_ioctl_desc *ioctl =
+                   &vmw_ioctls[nr - DRM_COMMAND_BASE];
+
+               if (unlikely(ioctl->cmd != cmd)) {
+                       DRM_ERROR("Invalid command format, ioctl %d\n",
+                                 nr - DRM_COMMAND_BASE);
+                       return -EINVAL;
+               }
+               return drm_ioctl(filp->f_path.dentry->d_inode,
+                                filp, cmd, arg);
+       }
+
+       /*
+        * Not all old drm ioctls are thread-safe.
+        */
+
+       lock_kernel();
+       ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+       return ret;
+}
+
+static int vmw_firstopen(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       dev_priv->is_opened = true;
+
+       return 0;
+}
+
+static void vmw_lastclose(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct drm_crtc *crtc;
+       struct drm_mode_set set;
+       int ret;
+
+       /**
+        * Do nothing on the lastclose call from drm_unload.
+        */
+
+       if (!dev_priv->is_opened)
+               return;
+
+       dev_priv->is_opened = false;
+       set.x = 0;
+       set.y = 0;
+       set.fb = NULL;
+       set.mode = NULL;
+       set.connectors = NULL;
+       set.num_connectors = 0;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               set.crtc = crtc;
+               ret = crtc->funcs->set_config(&set);
+               WARN_ON(ret != 0);
+       }
+
+}
+
+static void vmw_master_init(struct vmw_master *vmaster)
+{
+       ttm_lock_init(&vmaster->lock);
+}
+
+static int vmw_master_create(struct drm_device *dev,
+                            struct drm_master *master)
+{
+       struct vmw_master *vmaster;
+
+       DRM_INFO("Master create.\n");
+       vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
+       if (unlikely(vmaster == NULL))
+               return -ENOMEM;
+
+       ttm_lock_init(&vmaster->lock);
+       ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+       master->driver_priv = vmaster;
+
+       return 0;
+}
+
+static void vmw_master_destroy(struct drm_device *dev,
+                              struct drm_master *master)
+{
+       struct vmw_master *vmaster = vmw_master(master);
+
+       DRM_INFO("Master destroy.\n");
+       master->driver_priv = NULL;
+       kfree(vmaster);
+}
+
+
+static int vmw_master_set(struct drm_device *dev,
+                         struct drm_file *file_priv,
+                         bool from_open)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+       struct vmw_master *active = dev_priv->active_master;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+       int ret = 0;
+
+       DRM_INFO("Master set.\n");
+       if (dev_priv->stealth) {
+               ret = vmw_request_device(dev_priv);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       if (active) {
+               BUG_ON(active != &dev_priv->fbdev_master);
+               ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
+               if (unlikely(ret != 0))
+                       goto out_no_active_lock;
+
+               ttm_lock_set_kill(&active->lock, true, SIGTERM);
+               ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Unable to clean VRAM on "
+                                 "master drop.\n");
+               }
+
+               dev_priv->active_master = NULL;
+       }
+
+       ttm_lock_set_kill(&vmaster->lock, false, SIGTERM);
+       if (!from_open) {
+               ttm_vt_unlock(&vmaster->lock);
+               BUG_ON(vmw_fp->locked_master != file_priv->master);
+               drm_master_put(&vmw_fp->locked_master);
+       }
+
+       dev_priv->active_master = vmaster;
+
+       return 0;
+
+out_no_active_lock:
+       vmw_release_device(dev_priv);
+       return ret;
+}
+
+static void vmw_master_drop(struct drm_device *dev,
+                           struct drm_file *file_priv,
+                           bool from_release)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+       int ret;
+
+       DRM_INFO("Master drop.\n");
+
+       /**
+        * Make sure the master doesn't disappear while we have
+        * it locked.
+        */
+
+       vmw_fp->locked_master = drm_master_get(file_priv->master);
+       ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+
+       if (unlikely((ret != 0))) {
+               DRM_ERROR("Unable to lock TTM at VT switch.\n");
+               drm_master_put(&vmw_fp->locked_master);
+       }
+
+       ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+
+       if (dev_priv->stealth) {
+               ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
+               if (unlikely(ret != 0))
+                       DRM_ERROR("Unable to clean VRAM on master drop.\n");
+               vmw_release_device(dev_priv);
+       }
+       dev_priv->active_master = &dev_priv->fbdev_master;
+       ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+       ttm_vt_unlock(&dev_priv->fbdev_master.lock);
+
+       if (!dev_priv->stealth)
+               vmw_fb_on(dev_priv);
+}
+
+
+static void vmw_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+static struct drm_driver driver = {
+       .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+       DRIVER_MODESET,
+       .load = vmw_driver_load,
+       .unload = vmw_driver_unload,
+       .firstopen = vmw_firstopen,
+       .lastclose = vmw_lastclose,
+       .irq_preinstall = vmw_irq_preinstall,
+       .irq_postinstall = vmw_irq_postinstall,
+       .irq_uninstall = vmw_irq_uninstall,
+       .irq_handler = vmw_irq_handler,
+       .reclaim_buffers_locked = NULL,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .ioctls = vmw_ioctls,
+       .num_ioctls = DRM_ARRAY_SIZE(vmw_ioctls),
+       .dma_quiescent = NULL,  /*vmw_dma_quiescent, */
+       .master_create = vmw_master_create,
+       .master_destroy = vmw_master_destroy,
+       .master_set = vmw_master_set,
+       .master_drop = vmw_master_drop,
+       .open = vmw_driver_open,
+       .postclose = vmw_postclose,
+       .fops = {
+                .owner = THIS_MODULE,
+                .open = drm_open,
+                .release = drm_release,
+                .unlocked_ioctl = vmw_unlocked_ioctl,
+                .mmap = vmw_mmap,
+                .poll = drm_poll,
+                .fasync = drm_fasync,
+#if defined(CONFIG_COMPAT)
+                .compat_ioctl = drm_compat_ioctl,
+#endif
+                },
+       .pci_driver = {
+                      .name = VMWGFX_DRIVER_NAME,
+                      .id_table = vmw_pci_id_list,
+                      .probe = vmw_probe,
+                      .remove = vmw_remove
+                      },
+       .name = VMWGFX_DRIVER_NAME,
+       .desc = VMWGFX_DRIVER_DESC,
+       .date = VMWGFX_DRIVER_DATE,
+       .major = VMWGFX_DRIVER_MAJOR,
+       .minor = VMWGFX_DRIVER_MINOR,
+       .patchlevel = VMWGFX_DRIVER_PATCHLEVEL
+};
+
+static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_dev(pdev, ent, &driver);
+}
+
+static int __init vmwgfx_init(void)
+{
+       int ret;
+       ret = drm_init(&driver);
+       if (ret)
+               DRM_ERROR("Failed initializing DRM.\n");
+       return ret;
+}
+
+static void __exit vmwgfx_exit(void)
+{
+       drm_exit(&driver);
+}
+
+module_init(vmwgfx_init);
+module_exit(vmwgfx_exit);
+
+MODULE_AUTHOR("VMware Inc. and others");
+MODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
new file mode 100644 (file)
index 0000000..43546d0
--- /dev/null
@@ -0,0 +1,511 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _VMWGFX_DRV_H_
+#define _VMWGFX_DRV_H_
+
+#include "vmwgfx_reg.h"
+#include "drmP.h"
+#include "vmwgfx_drm.h"
+#include "drm_hashtab.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_object.h"
+#include "ttm/ttm_lock.h"
+#include "ttm/ttm_execbuf_util.h"
+#include "ttm/ttm_module.h"
+
+#define VMWGFX_DRIVER_DATE "20090724"
+#define VMWGFX_DRIVER_MAJOR 0
+#define VMWGFX_DRIVER_MINOR 1
+#define VMWGFX_DRIVER_PATCHLEVEL 2
+#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
+#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
+#define VMWGFX_MAX_RELOCATIONS 2048
+#define VMWGFX_MAX_GMRS 2048
+
+struct vmw_fpriv {
+       struct drm_master *locked_master;
+       struct ttm_object_file *tfile;
+};
+
+struct vmw_dma_buffer {
+       struct ttm_buffer_object base;
+       struct list_head validate_list;
+       struct list_head gmr_lru;
+       uint32_t gmr_id;
+       bool gmr_bound;
+       uint32_t cur_validate_node;
+       bool on_validate_list;
+};
+
+struct vmw_resource {
+       struct kref kref;
+       struct vmw_private *dev_priv;
+       struct idr *idr;
+       int id;
+       enum ttm_object_type res_type;
+       bool avail;
+       void (*hw_destroy) (struct vmw_resource *res);
+       void (*res_free) (struct vmw_resource *res);
+
+       /* TODO is a generic snooper needed? */
+#if 0
+       void (*snoop)(struct vmw_resource *res,
+                     struct ttm_object_file *tfile,
+                     SVGA3dCmdHeader *header);
+       void *snoop_priv;
+#endif
+};
+
+struct vmw_cursor_snooper {
+       struct drm_crtc *crtc;
+       size_t age;
+       uint32_t *image;
+};
+
+struct vmw_surface {
+       struct vmw_resource res;
+       uint32_t flags;
+       uint32_t format;
+       uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
+       struct drm_vmw_size *sizes;
+       uint32_t num_sizes;
+
+       /* TODO so far just a extra pointer */
+       struct vmw_cursor_snooper snooper;
+};
+
+struct vmw_fifo_state {
+       unsigned long reserved_size;
+       __le32 *dynamic_buffer;
+       __le32 *static_buffer;
+       __le32 *last_buffer;
+       uint32_t last_data_size;
+       uint32_t last_buffer_size;
+       bool last_buffer_add;
+       unsigned long static_buffer_size;
+       bool using_bounce_buffer;
+       uint32_t capabilities;
+       struct rw_semaphore rwsem;
+};
+
+struct vmw_relocation {
+       SVGAGuestPtr *location;
+       uint32_t index;
+};
+
+struct vmw_sw_context{
+       struct ida bo_list;
+       uint32_t last_cid;
+       bool cid_valid;
+       uint32_t last_sid;
+       bool sid_valid;
+       struct ttm_object_file *tfile;
+       struct list_head validate_nodes;
+       struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS];
+       uint32_t cur_reloc;
+       struct ttm_validate_buffer val_bufs[VMWGFX_MAX_GMRS];
+       uint32_t cur_val_buf;
+};
+
+struct vmw_legacy_display;
+struct vmw_overlay;
+
+struct vmw_master {
+       struct ttm_lock lock;
+};
+
+struct vmw_private {
+       struct ttm_bo_device bdev;
+       struct ttm_bo_global_ref bo_global_ref;
+       struct ttm_global_reference mem_global_ref;
+
+       struct vmw_fifo_state fifo;
+
+       struct drm_device *dev;
+       unsigned long vmw_chipset;
+       unsigned int io_start;
+       uint32_t vram_start;
+       uint32_t vram_size;
+       uint32_t mmio_start;
+       uint32_t mmio_size;
+       uint32_t fb_max_width;
+       uint32_t fb_max_height;
+       __le32 __iomem *mmio_virt;
+       int mmio_mtrr;
+       uint32_t capabilities;
+       uint32_t max_gmr_descriptors;
+       uint32_t max_gmr_ids;
+       struct mutex hw_mutex;
+
+       /*
+        * VGA registers.
+        */
+
+       uint32_t vga_width;
+       uint32_t vga_height;
+       uint32_t vga_depth;
+       uint32_t vga_bpp;
+       uint32_t vga_pseudo;
+       uint32_t vga_red_mask;
+       uint32_t vga_blue_mask;
+       uint32_t vga_green_mask;
+
+       /*
+        * Framebuffer info.
+        */
+
+       void *fb_info;
+       struct vmw_legacy_display *ldu_priv;
+       struct vmw_overlay *overlay_priv;
+
+       /*
+        * Context and surface management.
+        */
+
+       rwlock_t resource_lock;
+       struct idr context_idr;
+       struct idr surface_idr;
+       struct idr stream_idr;
+
+       /*
+        * Block lastclose from racing with firstopen.
+        */
+
+       struct mutex init_mutex;
+
+       /*
+        * A resource manager for kernel-only surfaces and
+        * contexts.
+        */
+
+       struct ttm_object_device *tdev;
+
+       /*
+        * Fencing and IRQs.
+        */
+
+       uint32_t fence_seq;
+       wait_queue_head_t fence_queue;
+       wait_queue_head_t fifo_queue;
+       atomic_t fence_queue_waiters;
+       atomic_t fifo_queue_waiters;
+       uint32_t last_read_sequence;
+       spinlock_t irq_lock;
+
+       /*
+        * Device state
+        */
+
+       uint32_t traces_state;
+       uint32_t enable_state;
+       uint32_t config_done_state;
+
+       /**
+        * Execbuf
+        */
+       /**
+        * Protected by the cmdbuf mutex.
+        */
+
+       struct vmw_sw_context ctx;
+       uint32_t val_seq;
+       struct mutex cmdbuf_mutex;
+
+       /**
+        * GMR management. Protected by the lru spinlock.
+        */
+
+       struct ida gmr_ida;
+       struct list_head gmr_lru;
+
+
+       /**
+        * Operating mode.
+        */
+
+       bool stealth;
+       bool is_opened;
+
+       /**
+        * Master management.
+        */
+
+       struct vmw_master *active_master;
+       struct vmw_master fbdev_master;
+};
+
+static inline struct vmw_private *vmw_priv(struct drm_device *dev)
+{
+       return (struct vmw_private *)dev->dev_private;
+}
+
+static inline struct vmw_fpriv *vmw_fpriv(struct drm_file *file_priv)
+{
+       return (struct vmw_fpriv *)file_priv->driver_priv;
+}
+
+static inline struct vmw_master *vmw_master(struct drm_master *master)
+{
+       return (struct vmw_master *) master->driver_priv;
+}
+
+static inline void vmw_write(struct vmw_private *dev_priv,
+                            unsigned int offset, uint32_t value)
+{
+       outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
+       outl(value, dev_priv->io_start + VMWGFX_VALUE_PORT);
+}
+
+static inline uint32_t vmw_read(struct vmw_private *dev_priv,
+                               unsigned int offset)
+{
+       uint32_t val;
+
+       outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
+       val = inl(dev_priv->io_start + VMWGFX_VALUE_PORT);
+       return val;
+}
+
+/**
+ * GMR utilities - vmwgfx_gmr.c
+ */
+
+extern int vmw_gmr_bind(struct vmw_private *dev_priv,
+                       struct ttm_buffer_object *bo);
+extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
+
+/**
+ * Resource utilities - vmwgfx_resource.c
+ */
+
+extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
+extern void vmw_resource_unreference(struct vmw_resource **p_res);
+extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res);
+extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+extern int vmw_context_check(struct vmw_private *dev_priv,
+                            struct ttm_object_file *tfile,
+                            int id);
+extern void vmw_surface_res_free(struct vmw_resource *res);
+extern int vmw_surface_init(struct vmw_private *dev_priv,
+                           struct vmw_surface *srf,
+                           void (*res_free) (struct vmw_resource *res));
+extern int vmw_user_surface_lookup(struct vmw_private *dev_priv,
+                                  struct ttm_object_file *tfile,
+                                  int sid, struct vmw_surface **out);
+extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
+                                      struct drm_file *file_priv);
+extern int vmw_surface_check(struct vmw_private *dev_priv,
+                            struct ttm_object_file *tfile,
+                            int id);
+extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo);
+extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
+                          struct vmw_dma_buffer *vmw_bo,
+                          size_t size, struct ttm_placement *placement,
+                          bool interuptable,
+                          void (*bo_free) (struct ttm_buffer_object *bo));
+extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv);
+extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv);
+extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
+                                        uint32_t cur_validate_node);
+extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
+extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
+                                 uint32_t id, struct vmw_dma_buffer **out);
+extern uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo);
+extern void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id);
+extern int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id);
+extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
+                                      struct vmw_dma_buffer *bo);
+extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
+                               struct vmw_dma_buffer *bo);
+extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv);
+extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv);
+extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
+                                 struct ttm_object_file *tfile,
+                                 uint32_t *inout_id,
+                                 struct vmw_resource **out);
+
+
+/**
+ * Misc Ioctl functionality - vmwgfx_ioctl.c
+ */
+
+extern int vmw_getparam_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+extern int vmw_fifo_debug_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+
+/**
+ * Fifo utilities - vmwgfx_fifo.c
+ */
+
+extern int vmw_fifo_init(struct vmw_private *dev_priv,
+                        struct vmw_fifo_state *fifo);
+extern void vmw_fifo_release(struct vmw_private *dev_priv,
+                            struct vmw_fifo_state *fifo);
+extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes);
+extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);
+extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
+                              uint32_t *sequence);
+extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
+extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/**
+ * TTM glue - vmwgfx_ttm_glue.c
+ */
+
+extern int vmw_ttm_global_init(struct vmw_private *dev_priv);
+extern void vmw_ttm_global_release(struct vmw_private *dev_priv);
+extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/**
+ * TTM buffer object driver - vmwgfx_buffer.c
+ */
+
+extern struct ttm_placement vmw_vram_placement;
+extern struct ttm_placement vmw_vram_ne_placement;
+extern struct ttm_placement vmw_sys_placement;
+extern struct ttm_bo_driver vmw_bo_driver;
+extern int vmw_dma_quiescent(struct drm_device *dev);
+
+/**
+ * Command submission - vmwgfx_execbuf.c
+ */
+
+extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+
+/**
+ * IRQs and wating - vmwgfx_irq.c
+ */
+
+extern irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS);
+extern int vmw_wait_fence(struct vmw_private *dev_priv, bool lazy,
+                         uint32_t sequence, bool interruptible,
+                         unsigned long timeout);
+extern void vmw_irq_preinstall(struct drm_device *dev);
+extern int vmw_irq_postinstall(struct drm_device *dev);
+extern void vmw_irq_uninstall(struct drm_device *dev);
+extern bool vmw_fence_signaled(struct vmw_private *dev_priv,
+                              uint32_t sequence);
+extern int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+extern int vmw_fallback_wait(struct vmw_private *dev_priv,
+                            bool lazy,
+                            bool fifo_idle,
+                            uint32_t sequence,
+                            bool interruptible,
+                            unsigned long timeout);
+
+/**
+ * Kernel framebuffer - vmwgfx_fb.c
+ */
+
+int vmw_fb_init(struct vmw_private *vmw_priv);
+int vmw_fb_close(struct vmw_private *dev_priv);
+int vmw_fb_off(struct vmw_private *vmw_priv);
+int vmw_fb_on(struct vmw_private *vmw_priv);
+
+/**
+ * Kernel modesetting - vmwgfx_kms.c
+ */
+
+int vmw_kms_init(struct vmw_private *dev_priv);
+int vmw_kms_close(struct vmw_private *dev_priv);
+int vmw_kms_save_vga(struct vmw_private *vmw_priv);
+int vmw_kms_restore_vga(struct vmw_private *vmw_priv);
+int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv);
+void vmw_kms_cursor_snoop(struct vmw_surface *srf,
+                         struct ttm_object_file *tfile,
+                         struct ttm_buffer_object *bo,
+                         SVGA3dCmdHeader *header);
+
+/**
+ * Overlay control - vmwgfx_overlay.c
+ */
+
+int vmw_overlay_init(struct vmw_private *dev_priv);
+int vmw_overlay_close(struct vmw_private *dev_priv);
+int vmw_overlay_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+int vmw_overlay_stop_all(struct vmw_private *dev_priv);
+int vmw_overlay_resume_all(struct vmw_private *dev_priv);
+int vmw_overlay_pause_all(struct vmw_private *dev_priv);
+int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out);
+int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
+int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
+int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
+
+/**
+ * Inline helper functions
+ */
+
+static inline void vmw_surface_unreference(struct vmw_surface **srf)
+{
+       struct vmw_surface *tmp_srf = *srf;
+       struct vmw_resource *res = &tmp_srf->res;
+       *srf = NULL;
+
+       vmw_resource_unreference(&res);
+}
+
+static inline struct vmw_surface *vmw_surface_reference(struct vmw_surface *srf)
+{
+       (void) vmw_resource_reference(&srf->res);
+       return srf;
+}
+
+static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf)
+{
+       struct vmw_dma_buffer *tmp_buf = *buf;
+       struct ttm_buffer_object *bo = &tmp_buf->base;
+       *buf = NULL;
+
+       ttm_bo_unref(&bo);
+}
+
+static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer *buf)
+{
+       if (ttm_bo_reference(&buf->base))
+               return buf;
+       return NULL;
+}
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
new file mode 100644 (file)
index 0000000..7a39f3e
--- /dev/null
@@ -0,0 +1,516 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "vmwgfx_reg.h"
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_placement.h"
+
+static int vmw_cmd_invalid(struct vmw_private *dev_priv,
+                          struct vmw_sw_context *sw_context,
+                          SVGA3dCmdHeader *header)
+{
+       return capable(CAP_SYS_ADMIN) ? : -EINVAL;
+}
+
+static int vmw_cmd_ok(struct vmw_private *dev_priv,
+                     struct vmw_sw_context *sw_context,
+                     SVGA3dCmdHeader *header)
+{
+       return 0;
+}
+
+static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
+                            struct vmw_sw_context *sw_context,
+                            SVGA3dCmdHeader *header)
+{
+       struct vmw_cid_cmd {
+               SVGA3dCmdHeader header;
+               __le32 cid;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_cid_cmd, header);
+       if (likely(sw_context->cid_valid && cmd->cid == sw_context->last_cid))
+               return 0;
+
+       ret = vmw_context_check(dev_priv, sw_context->tfile, cmd->cid);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not find or use context %u\n",
+                         (unsigned) cmd->cid);
+               return ret;
+       }
+
+       sw_context->last_cid = cmd->cid;
+       sw_context->cid_valid = true;
+
+       return 0;
+}
+
+static int vmw_cmd_sid_check(struct vmw_private *dev_priv,
+                            struct vmw_sw_context *sw_context,
+                            uint32_t sid)
+{
+       if (unlikely((!sw_context->sid_valid || sid != sw_context->last_sid) &&
+                    sid != SVGA3D_INVALID_ID)) {
+               int ret = vmw_surface_check(dev_priv, sw_context->tfile, sid);
+
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Could ot find or use surface %u\n",
+                                 (unsigned) sid);
+                       return ret;
+               }
+
+               sw_context->last_sid = sid;
+               sw_context->sid_valid = true;
+       }
+       return 0;
+}
+
+
+static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
+                                          struct vmw_sw_context *sw_context,
+                                          SVGA3dCmdHeader *header)
+{
+       struct vmw_sid_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetRenderTarget body;
+       } *cmd;
+       int ret;
+
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.target.sid);
+}
+
+static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
+                                     struct vmw_sw_context *sw_context,
+                                     SVGA3dCmdHeader *header)
+{
+       struct vmw_sid_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSurfaceCopy body;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+       if (unlikely(ret != 0))
+               return ret;
+       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+}
+
+static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct vmw_sid_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSurfaceStretchBlt body;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+       if (unlikely(ret != 0))
+               return ret;
+       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+}
+
+static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
+                                        struct vmw_sw_context *sw_context,
+                                        SVGA3dCmdHeader *header)
+{
+       struct vmw_sid_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBlitSurfaceToScreen body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.srcImage.sid);
+}
+
+static int vmw_cmd_present_check(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGA3dCmdHeader *header)
+{
+       struct vmw_sid_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdPresent body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.sid);
+}
+
+static int vmw_cmd_dma(struct vmw_private *dev_priv,
+                      struct vmw_sw_context *sw_context,
+                      SVGA3dCmdHeader *header)
+{
+       uint32_t handle;
+       struct vmw_dma_buffer *vmw_bo = NULL;
+       struct ttm_buffer_object *bo;
+       struct vmw_surface *srf = NULL;
+       struct vmw_dma_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSurfaceDMA dma;
+       } *cmd;
+       struct vmw_relocation *reloc;
+       int ret;
+       uint32_t cur_validate_node;
+       struct ttm_validate_buffer *val_buf;
+
+
+       cmd = container_of(header, struct vmw_dma_cmd, header);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->dma.host.sid);
+       if (unlikely(ret != 0))
+               return ret;
+
+       handle = cmd->dma.guest.ptr.gmrId;
+       ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not find or use GMR region.\n");
+               return -EINVAL;
+       }
+       bo = &vmw_bo->base;
+
+       if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
+               DRM_ERROR("Max number of DMA commands per submission"
+                         " exceeded\n");
+               ret = -EINVAL;
+               goto out_no_reloc;
+       }
+
+       reloc = &sw_context->relocs[sw_context->cur_reloc++];
+       reloc->location = &cmd->dma.guest.ptr;
+
+       cur_validate_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf);
+       if (unlikely(cur_validate_node >= VMWGFX_MAX_GMRS)) {
+               DRM_ERROR("Max number of DMA buffers per submission"
+                         " exceeded.\n");
+               ret = -EINVAL;
+               goto out_no_reloc;
+       }
+
+       reloc->index = cur_validate_node;
+       if (unlikely(cur_validate_node == sw_context->cur_val_buf)) {
+               val_buf = &sw_context->val_bufs[cur_validate_node];
+               val_buf->bo = ttm_bo_reference(bo);
+               val_buf->new_sync_obj_arg = (void *) dev_priv;
+               list_add_tail(&val_buf->head, &sw_context->validate_nodes);
+               ++sw_context->cur_val_buf;
+       }
+
+       ret = vmw_user_surface_lookup(dev_priv, sw_context->tfile,
+                                     cmd->dma.host.sid, &srf);
+       if (ret) {
+               DRM_ERROR("could not find surface\n");
+               goto out_no_reloc;
+       }
+
+       vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header);
+       vmw_surface_unreference(&srf);
+
+out_no_reloc:
+       vmw_dmabuf_unreference(&vmw_bo);
+       return ret;
+}
+
+
+typedef int (*vmw_cmd_func) (struct vmw_private *,
+                            struct vmw_sw_context *,
+                            SVGA3dCmdHeader *);
+
+#define VMW_CMD_DEF(cmd, func) \
+       [cmd - SVGA_3D_CMD_BASE] = func
+
+static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma),
+       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid),
+       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
+                   &vmw_cmd_set_render_target_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
+       VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
+                   &vmw_cmd_blt_surf_screen_check)
+};
+
+static int vmw_cmd_check(struct vmw_private *dev_priv,
+                        struct vmw_sw_context *sw_context,
+                        void *buf, uint32_t *size)
+{
+       uint32_t cmd_id;
+       SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
+       int ret;
+
+       cmd_id = ((uint32_t *)buf)[0];
+       if (cmd_id == SVGA_CMD_UPDATE) {
+               *size = 5 << 2;
+               return 0;
+       }
+
+       cmd_id = le32_to_cpu(header->id);
+       *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader);
+
+       cmd_id -= SVGA_3D_CMD_BASE;
+       if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
+               goto out_err;
+
+       ret = vmw_cmd_funcs[cmd_id](dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               goto out_err;
+
+       return 0;
+out_err:
+       DRM_ERROR("Illegal / Invalid SVGA3D command: %d\n",
+                 cmd_id + SVGA_3D_CMD_BASE);
+       return -EINVAL;
+}
+
+static int vmw_cmd_check_all(struct vmw_private *dev_priv,
+                            struct vmw_sw_context *sw_context,
+                            void *buf, uint32_t size)
+{
+       int32_t cur_size = size;
+       int ret;
+
+       while (cur_size > 0) {
+               ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
+               if (unlikely(ret != 0))
+                       return ret;
+               buf = (void *)((unsigned long) buf + size);
+               cur_size -= size;
+       }
+
+       if (unlikely(cur_size != 0)) {
+               DRM_ERROR("Command verifier out of sync.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void vmw_free_relocations(struct vmw_sw_context *sw_context)
+{
+       sw_context->cur_reloc = 0;
+}
+
+static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
+{
+       uint32_t i;
+       struct vmw_relocation *reloc;
+       struct ttm_validate_buffer *validate;
+       struct ttm_buffer_object *bo;
+
+       for (i = 0; i < sw_context->cur_reloc; ++i) {
+               reloc = &sw_context->relocs[i];
+               validate = &sw_context->val_bufs[reloc->index];
+               bo = validate->bo;
+               reloc->location->offset += bo->offset;
+               reloc->location->gmrId = vmw_dmabuf_gmr(bo);
+       }
+       vmw_free_relocations(sw_context);
+}
+
+static void vmw_clear_validations(struct vmw_sw_context *sw_context)
+{
+       struct ttm_validate_buffer *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &sw_context->validate_nodes,
+                                head) {
+               list_del(&entry->head);
+               vmw_dmabuf_validate_clear(entry->bo);
+               ttm_bo_unref(&entry->bo);
+               sw_context->cur_val_buf--;
+       }
+       BUG_ON(sw_context->cur_val_buf != 0);
+}
+
+static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
+                                     struct ttm_buffer_object *bo)
+{
+       int ret;
+
+       if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
+               return 0;
+
+       ret = vmw_gmr_bind(dev_priv, bo);
+       if (likely(ret == 0 || ret == -ERESTART))
+               return ret;
+
+
+       ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false);
+       return ret;
+}
+
+
+static int vmw_validate_buffers(struct vmw_private *dev_priv,
+                               struct vmw_sw_context *sw_context)
+{
+       struct ttm_validate_buffer *entry;
+       int ret;
+
+       list_for_each_entry(entry, &sw_context->validate_nodes, head) {
+               ret = vmw_validate_single_buffer(dev_priv, entry->bo);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+       return 0;
+}
+
+int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
+       struct drm_vmw_fence_rep fence_rep;
+       struct drm_vmw_fence_rep __user *user_fence_rep;
+       int ret;
+       void *user_cmd;
+       void *cmd;
+       uint32_t sequence;
+       struct vmw_sw_context *sw_context = &dev_priv->ctx;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
+       if (unlikely(ret != 0)) {
+               ret = -ERESTART;
+               goto out_no_cmd_mutex;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, arg->command_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving fifo space for commands.\n");
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       user_cmd = (void __user *)(unsigned long)arg->commands;
+       ret = copy_from_user(cmd, user_cmd, arg->command_size);
+
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed copying commands.\n");
+               goto out_commit;
+       }
+
+       sw_context->tfile = vmw_fpriv(file_priv)->tfile;
+       sw_context->cid_valid = false;
+       sw_context->sid_valid = false;
+       sw_context->cur_reloc = 0;
+       sw_context->cur_val_buf = 0;
+
+       INIT_LIST_HEAD(&sw_context->validate_nodes);
+
+       ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size);
+       if (unlikely(ret != 0))
+               goto out_err;
+       ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes,
+                                    dev_priv->val_seq++);
+       if (unlikely(ret != 0))
+               goto out_err;
+
+       ret = vmw_validate_buffers(dev_priv, sw_context);
+       if (unlikely(ret != 0))
+               goto out_err;
+
+       vmw_apply_relocations(sw_context);
+       vmw_fifo_commit(dev_priv, arg->command_size);
+
+       ret = vmw_fifo_send_fence(dev_priv, &sequence);
+
+       ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
+                                   (void *)(unsigned long) sequence);
+       vmw_clear_validations(sw_context);
+       mutex_unlock(&dev_priv->cmdbuf_mutex);
+
+       /*
+        * This error is harmless, because if fence submission fails,
+        * vmw_fifo_send_fence will sync.
+        */
+
+       if (ret != 0)
+               DRM_ERROR("Fence submission error. Syncing.\n");
+
+       fence_rep.error = ret;
+       fence_rep.fence_seq = (uint64_t) sequence;
+
+       user_fence_rep = (struct drm_vmw_fence_rep __user *)
+           (unsigned long)arg->fence_rep;
+
+       /*
+        * copy_to_user errors will be detected by user space not
+        * seeing fence_rep::error filled in.
+        */
+
+       ret = copy_to_user(user_fence_rep, &fence_rep, sizeof(fence_rep));
+
+       vmw_kms_cursor_post_execbuf(dev_priv);
+       ttm_read_unlock(&vmaster->lock);
+       return 0;
+out_err:
+       vmw_free_relocations(sw_context);
+       ttm_eu_backoff_reservation(&sw_context->validate_nodes);
+       vmw_clear_validations(sw_context);
+out_commit:
+       vmw_fifo_commit(dev_priv, 0);
+out_unlock:
+       mutex_unlock(&dev_priv->cmdbuf_mutex);
+out_no_cmd_mutex:
+       ttm_read_unlock(&vmaster->lock);
+       return ret;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
new file mode 100644 (file)
index 0000000..641dde7
--- /dev/null
@@ -0,0 +1,742 @@
+/**************************************************************************
+ *
+ * Copyright © 2007 David Airlie
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+#include "ttm/ttm_placement.h"
+
+#define VMW_DIRTY_DELAY (HZ / 30)
+
+struct vmw_fb_par {
+       struct vmw_private *vmw_priv;
+
+       void *vmalloc;
+
+       struct vmw_dma_buffer *vmw_bo;
+       struct ttm_bo_kmap_obj map;
+
+       u32 pseudo_palette[17];
+
+       unsigned depth;
+       unsigned bpp;
+
+       unsigned max_width;
+       unsigned max_height;
+
+       void *bo_ptr;
+       unsigned bo_size;
+       bool bo_iowrite;
+
+       struct {
+               spinlock_t lock;
+               bool active;
+               unsigned x1;
+               unsigned y1;
+               unsigned x2;
+               unsigned y2;
+       } dirty;
+};
+
+static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *info)
+{
+       struct vmw_fb_par *par = info->par;
+       u32 *pal = par->pseudo_palette;
+
+       if (regno > 15) {
+               DRM_ERROR("Bad regno %u.\n", regno);
+               return 1;
+       }
+
+       switch (par->depth) {
+       case 24:
+       case 32:
+               pal[regno] = ((red & 0xff00) << 8) |
+                             (green & 0xff00) |
+                            ((blue  & 0xff00) >> 8);
+               break;
+       default:
+               DRM_ERROR("Bad depth %u, bpp %u.\n", par->depth, par->bpp);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int vmw_fb_check_var(struct fb_var_screeninfo *var,
+                           struct fb_info *info)
+{
+       int depth = var->bits_per_pixel;
+       struct vmw_fb_par *par = info->par;
+       struct vmw_private *vmw_priv = par->vmw_priv;
+
+       switch (var->bits_per_pixel) {
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       switch (depth) {
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               DRM_ERROR("Bad depth %u.\n", depth);
+               return -EINVAL;
+       }
+
+       /* without multimon its hard to resize */
+       if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) &&
+           (var->xres != par->max_width ||
+            var->yres != par->max_height)) {
+               DRM_ERROR("Tried to resize, but we don't have multimon\n");
+               return -EINVAL;
+       }
+
+       if (var->xres > par->max_width ||
+           var->yres > par->max_height) {
+               DRM_ERROR("Requested geom can not fit in framebuffer\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vmw_fb_set_par(struct fb_info *info)
+{
+       struct vmw_fb_par *par = info->par;
+       struct vmw_private *vmw_priv = par->vmw_priv;
+
+       if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
+               vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+
+               vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);
+               vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width);
+               vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height);
+               vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp);
+               vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth);
+               vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
+               vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
+               vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
+
+               /* TODO check if pitch and offset changes */
+
+               vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, info->var.yoffset);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+       } else {
+               vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres);
+               vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres);
+
+               /* TODO check if pitch and offset changes */
+       }
+
+       return 0;
+}
+
+static int vmw_fb_pan_display(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       return 0;
+}
+
+static int vmw_fb_blank(int blank, struct fb_info *info)
+{
+       return 0;
+}
+
+/*
+ * Dirty code
+ */
+
+static void vmw_fb_dirty_flush(struct vmw_fb_par *par)
+{
+       struct vmw_private *vmw_priv = par->vmw_priv;
+       struct fb_info *info = vmw_priv->fb_info;
+       int stride = (info->fix.line_length / 4);
+       int *src = (int *)info->screen_base;
+       __le32 __iomem *vram_mem = par->bo_ptr;
+       unsigned long flags;
+       unsigned x, y, w, h;
+       int i, k;
+       struct {
+               uint32_t header;
+               SVGAFifoCmdUpdate body;
+       } *cmd;
+
+       spin_lock_irqsave(&par->dirty.lock, flags);
+       if (!par->dirty.active) {
+               spin_unlock_irqrestore(&par->dirty.lock, flags);
+               return;
+       }
+       x = par->dirty.x1;
+       y = par->dirty.y1;
+       w = min(par->dirty.x2, info->var.xres) - x;
+       h = min(par->dirty.y2, info->var.yres) - y;
+       par->dirty.x1 = par->dirty.x2 = 0;
+       par->dirty.y1 = par->dirty.y2 = 0;
+       spin_unlock_irqrestore(&par->dirty.lock, flags);
+
+       for (i = y * stride; i < info->fix.smem_len / 4; i += stride) {
+               for (k = i+x; k < i+x+w && k < info->fix.smem_len / 4; k++)
+                       iowrite32(src[k], vram_mem + k);
+       }
+
+#if 0
+       DRM_INFO("%s, (%u, %u) (%ux%u)\n", __func__, x, y, w, h);
+#endif
+
+       cmd = vmw_fifo_reserve(vmw_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               return;
+       }
+
+       cmd->header = cpu_to_le32(SVGA_CMD_UPDATE);
+       cmd->body.x = cpu_to_le32(x);
+       cmd->body.y = cpu_to_le32(y);
+       cmd->body.width = cpu_to_le32(w);
+       cmd->body.height = cpu_to_le32(h);
+       vmw_fifo_commit(vmw_priv, sizeof(*cmd));
+}
+
+static void vmw_fb_dirty_mark(struct vmw_fb_par *par,
+                             unsigned x1, unsigned y1,
+                             unsigned width, unsigned height)
+{
+       struct fb_info *info = par->vmw_priv->fb_info;
+       unsigned long flags;
+       unsigned x2 = x1 + width;
+       unsigned y2 = y1 + height;
+
+       spin_lock_irqsave(&par->dirty.lock, flags);
+       if (par->dirty.x1 == par->dirty.x2) {
+               par->dirty.x1 = x1;
+               par->dirty.y1 = y1;
+               par->dirty.x2 = x2;
+               par->dirty.y2 = y2;
+               /* if we are active start the dirty work
+                * we share the work with the defio system */
+               if (par->dirty.active)
+                       schedule_delayed_work(&info->deferred_work, VMW_DIRTY_DELAY);
+       } else {
+               if (x1 < par->dirty.x1)
+                       par->dirty.x1 = x1;
+               if (y1 < par->dirty.y1)
+                       par->dirty.y1 = y1;
+               if (x2 > par->dirty.x2)
+                       par->dirty.x2 = x2;
+               if (y2 > par->dirty.y2)
+                       par->dirty.y2 = y2;
+       }
+       spin_unlock_irqrestore(&par->dirty.lock, flags);
+}
+
+static void vmw_deferred_io(struct fb_info *info,
+                           struct list_head *pagelist)
+{
+       struct vmw_fb_par *par = info->par;
+       unsigned long start, end, min, max;
+       unsigned long flags;
+       struct page *page;
+       int y1, y2;
+
+       min = ULONG_MAX;
+       max = 0;
+       list_for_each_entry(page, pagelist, lru) {
+               start = page->index << PAGE_SHIFT;
+               end = start + PAGE_SIZE - 1;
+               min = min(min, start);
+               max = max(max, end);
+       }
+
+       if (min < max) {
+               y1 = min / info->fix.line_length;
+               y2 = (max / info->fix.line_length) + 1;
+
+               spin_lock_irqsave(&par->dirty.lock, flags);
+               par->dirty.x1 = 0;
+               par->dirty.y1 = y1;
+               par->dirty.x2 = info->var.xres;
+               par->dirty.y2 = y2;
+               spin_unlock_irqrestore(&par->dirty.lock, flags);
+       }
+
+       vmw_fb_dirty_flush(par);
+};
+
+struct fb_deferred_io vmw_defio = {
+       .delay          = VMW_DIRTY_DELAY,
+       .deferred_io    = vmw_deferred_io,
+};
+
+/*
+ * Draw code
+ */
+
+static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       cfb_fillrect(info, rect);
+       vmw_fb_dirty_mark(info->par, rect->dx, rect->dy,
+                         rect->width, rect->height);
+}
+
+static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+       cfb_copyarea(info, region);
+       vmw_fb_dirty_mark(info->par, region->dx, region->dy,
+                         region->width, region->height);
+}
+
+static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       cfb_imageblit(info, image);
+       vmw_fb_dirty_mark(info->par, image->dx, image->dy,
+                         image->width, image->height);
+}
+
+/*
+ * Bring up code
+ */
+
+static struct fb_ops vmw_fb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = vmw_fb_check_var,
+       .fb_set_par = vmw_fb_set_par,
+       .fb_setcolreg = vmw_fb_setcolreg,
+       .fb_fillrect = vmw_fb_fillrect,
+       .fb_copyarea = vmw_fb_copyarea,
+       .fb_imageblit = vmw_fb_imageblit,
+       .fb_pan_display = vmw_fb_pan_display,
+       .fb_blank = vmw_fb_blank,
+};
+
+static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
+                           size_t size, struct vmw_dma_buffer **out)
+{
+       struct vmw_dma_buffer *vmw_bo;
+       struct ttm_placement ne_placement = vmw_vram_ne_placement;
+       int ret;
+
+       ne_placement.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       /* interuptable? */
+       ret = ttm_write_lock(&vmw_priv->fbdev_master.lock, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL);
+       if (!vmw_bo)
+               goto err_unlock;
+
+       ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size,
+                             &ne_placement,
+                             false,
+                             &vmw_dmabuf_bo_free);
+       if (unlikely(ret != 0))
+               goto err_unlock; /* init frees the buffer on failure */
+
+       *out = vmw_bo;
+
+       ttm_write_unlock(&vmw_priv->fbdev_master.lock);
+
+       return 0;
+
+err_unlock:
+       ttm_write_unlock(&vmw_priv->fbdev_master.lock);
+       return ret;
+}
+
+int vmw_fb_init(struct vmw_private *vmw_priv)
+{
+       struct device *device = &vmw_priv->dev->pdev->dev;
+       struct vmw_fb_par *par;
+       struct fb_info *info;
+       unsigned initial_width, initial_height;
+       unsigned fb_width, fb_height;
+       unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size;
+       int ret;
+
+       initial_width = 800;
+       initial_height = 600;
+
+       fb_bbp = 32;
+       fb_depth = 24;
+
+       if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
+               fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
+               fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
+       } else {
+               fb_width = min(vmw_priv->fb_max_width, initial_width);
+               fb_height = min(vmw_priv->fb_max_height, initial_height);
+       }
+
+       initial_width = min(fb_width, initial_width);
+       initial_height = min(fb_height, initial_height);
+
+       vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width);
+       vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height);
+       vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp);
+       vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth);
+       vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
+       vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
+       vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
+
+       fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE);
+       fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET);
+       fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE);
+
+       DRM_DEBUG("width  %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH));
+       DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT));
+       DRM_DEBUG("width  %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH));
+       DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT));
+       DRM_DEBUG("bpp    %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL));
+       DRM_DEBUG("depth  %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH));
+       DRM_DEBUG("bpl    %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE));
+       DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK));
+       DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK));
+       DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK));
+       DRM_DEBUG("fb_offset 0x%08x\n", fb_offset);
+       DRM_DEBUG("fb_pitch  %u\n", fb_pitch);
+       DRM_DEBUG("fb_size   %u kiB\n", fb_size / 1024);
+
+       info = framebuffer_alloc(sizeof(*par), device);
+       if (!info)
+               return -ENOMEM;
+
+       /*
+        * Par
+        */
+       vmw_priv->fb_info = info;
+       par = info->par;
+       par->vmw_priv = vmw_priv;
+       par->depth = fb_depth;
+       par->bpp = fb_bbp;
+       par->vmalloc = NULL;
+       par->max_width = fb_width;
+       par->max_height = fb_height;
+
+       /*
+        * Create buffers and alloc memory
+        */
+       par->vmalloc = vmalloc(fb_size);
+       if (unlikely(par->vmalloc == NULL)) {
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       ret = vmw_fb_create_bo(vmw_priv, fb_size, &par->vmw_bo);
+       if (unlikely(ret != 0))
+               goto err_free;
+
+       ret = ttm_bo_kmap(&par->vmw_bo->base,
+                         0,
+                         par->vmw_bo->base.num_pages,
+                         &par->map);
+       if (unlikely(ret != 0))
+               goto err_unref;
+       par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
+       par->bo_size = fb_size;
+
+       /*
+        * Fixed and var
+        */
+       strcpy(info->fix.id, "svgadrmfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.line_length = fb_pitch;
+
+       info->fix.smem_start = 0;
+       info->fix.smem_len = fb_size;
+
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
+
+       info->pseudo_palette = par->pseudo_palette;
+       info->screen_base = par->vmalloc;
+       info->screen_size = fb_size;
+
+       info->flags = FBINFO_DEFAULT;
+       info->fbops = &vmw_fb_ops;
+
+       /* 24 depth per default */
+       info->var.red.offset = 16;
+       info->var.green.offset = 8;
+       info->var.blue.offset = 0;
+       info->var.red.length = 8;
+       info->var.green.length = 8;
+       info->var.blue.length = 8;
+       info->var.transp.offset = 0;
+       info->var.transp.length = 0;
+
+       info->var.xres_virtual = fb_width;
+       info->var.yres_virtual = fb_height;
+       info->var.bits_per_pixel = par->bpp;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+
+       info->var.xres = initial_width;
+       info->var.yres = initial_height;
+
+#if 0
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+#else
+       info->pixmap.size = 0;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+#endif
+
+       /*
+        * Dirty & Deferred IO
+        */
+       par->dirty.x1 = par->dirty.x2 = 0;
+       par->dirty.y1 = par->dirty.y1 = 0;
+       par->dirty.active = true;
+       spin_lock_init(&par->dirty.lock);
+       info->fbdefio = &vmw_defio;
+       fb_deferred_io_init(info);
+
+       ret = register_framebuffer(info);
+       if (unlikely(ret != 0))
+               goto err_defio;
+
+       return 0;
+
+err_defio:
+       fb_deferred_io_cleanup(info);
+       ttm_bo_kunmap(&par->map);
+err_unref:
+       ttm_bo_unref((struct ttm_buffer_object **)&par->vmw_bo);
+err_free:
+       vfree(par->vmalloc);
+       framebuffer_release(info);
+       vmw_priv->fb_info = NULL;
+
+       return ret;
+}
+
+int vmw_fb_close(struct vmw_private *vmw_priv)
+{
+       struct fb_info *info;
+       struct vmw_fb_par *par;
+       struct ttm_buffer_object *bo;
+
+       if (!vmw_priv->fb_info)
+               return 0;
+
+       info = vmw_priv->fb_info;
+       par = info->par;
+       bo = &par->vmw_bo->base;
+       par->vmw_bo = NULL;
+
+       /* ??? order */
+       fb_deferred_io_cleanup(info);
+       unregister_framebuffer(info);
+
+       ttm_bo_kunmap(&par->map);
+       ttm_bo_unref(&bo);
+
+       vfree(par->vmalloc);
+       framebuffer_release(info);
+
+       return 0;
+}
+
+int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
+                        struct vmw_dma_buffer *vmw_bo)
+{
+       struct ttm_buffer_object *bo = &vmw_bo->base;
+       int ret = 0;
+
+       ret = ttm_bo_reserve(bo, false, false, false, 0);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_bo_validate(bo, &vmw_sys_placement, false, false);
+       ttm_bo_unreserve(bo);
+
+       return ret;
+}
+
+int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
+                               struct vmw_dma_buffer *vmw_bo)
+{
+       struct ttm_buffer_object *bo = &vmw_bo->base;
+       struct ttm_placement ne_placement = vmw_vram_ne_placement;
+       int ret = 0;
+
+       ne_placement.lpfn = bo->num_pages;
+
+       /* interuptable? */
+       ret = ttm_write_lock(&vmw_priv->active_master->lock, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_bo_reserve(bo, false, false, false, 0);
+       if (unlikely(ret != 0))
+               goto err_unlock;
+
+       if (vmw_bo->gmr_bound) {
+               vmw_gmr_unbind(vmw_priv, vmw_bo->gmr_id);
+               spin_lock(&bo->glob->lru_lock);
+               ida_remove(&vmw_priv->gmr_ida, vmw_bo->gmr_id);
+               spin_unlock(&bo->glob->lru_lock);
+               vmw_bo->gmr_bound = NULL;
+       }
+
+       ret = ttm_bo_validate(bo, &ne_placement, false, false);
+       ttm_bo_unreserve(bo);
+err_unlock:
+       ttm_write_unlock(&vmw_priv->active_master->lock);
+
+       return ret;
+}
+
+int vmw_fb_off(struct vmw_private *vmw_priv)
+{
+       struct fb_info *info;
+       struct vmw_fb_par *par;
+       unsigned long flags;
+
+       if (!vmw_priv->fb_info)
+               return -EINVAL;
+
+       info = vmw_priv->fb_info;
+       par = info->par;
+
+       spin_lock_irqsave(&par->dirty.lock, flags);
+       par->dirty.active = false;
+       spin_unlock_irqrestore(&par->dirty.lock, flags);
+
+       flush_scheduled_work();
+
+       par->bo_ptr = NULL;
+       ttm_bo_kunmap(&par->map);
+
+       vmw_dmabuf_from_vram(vmw_priv, par->vmw_bo);
+
+       return 0;
+}
+
+int vmw_fb_on(struct vmw_private *vmw_priv)
+{
+       struct fb_info *info;
+       struct vmw_fb_par *par;
+       unsigned long flags;
+       bool dummy;
+       int ret;
+
+       if (!vmw_priv->fb_info)
+               return -EINVAL;
+
+       info = vmw_priv->fb_info;
+       par = info->par;
+
+       /* we are already active */
+       if (par->bo_ptr != NULL)
+               return 0;
+
+       /* Make sure that all overlays are stoped when we take over */
+       vmw_overlay_stop_all(vmw_priv);
+
+       ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("could not move buffer to start of VRAM\n");
+               goto err_no_buffer;
+       }
+
+       ret = ttm_bo_kmap(&par->vmw_bo->base,
+                         0,
+                         par->vmw_bo->base.num_pages,
+                         &par->map);
+       BUG_ON(ret != 0);
+       par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &dummy);
+
+       spin_lock_irqsave(&par->dirty.lock, flags);
+       par->dirty.active = true;
+       spin_unlock_irqrestore(&par->dirty.lock, flags);
+
+err_no_buffer:
+       vmw_fb_set_par(info);
+
+       vmw_fb_dirty_mark(par, 0, 0, info->var.xres, info->var.yres);
+
+       /* If there already was stuff dirty we wont
+        * schedule a new work, so lets do it now */
+       schedule_delayed_work(&info->deferred_work, 0);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
new file mode 100644 (file)
index 0000000..76b0693
--- /dev/null
@@ -0,0 +1,521 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "drmP.h"
+#include "ttm/ttm_placement.h"
+
+int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       uint32_t max;
+       uint32_t min;
+       uint32_t dummy;
+       int ret;
+
+       fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE;
+       fifo->static_buffer = vmalloc(fifo->static_buffer_size);
+       if (unlikely(fifo->static_buffer == NULL))
+               return -ENOMEM;
+
+       fifo->last_buffer_size = VMWGFX_FIFO_STATIC_SIZE;
+       fifo->last_data_size = 0;
+       fifo->last_buffer_add = false;
+       fifo->last_buffer = vmalloc(fifo->last_buffer_size);
+       if (unlikely(fifo->last_buffer == NULL)) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       fifo->dynamic_buffer = NULL;
+       fifo->reserved_size = 0;
+       fifo->using_bounce_buffer = false;
+
+       init_rwsem(&fifo->rwsem);
+
+       /*
+        * Allow mapping the first page read-only to user-space.
+        */
+
+       DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH));
+       DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT));
+       DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL));
+
+       mutex_lock(&dev_priv->hw_mutex);
+       dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE);
+       dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE);
+       vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
+
+       min = 4;
+       if (dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)
+               min = vmw_read(dev_priv, SVGA_REG_MEM_REGS);
+       min <<= 2;
+
+       if (min < PAGE_SIZE)
+               min = PAGE_SIZE;
+
+       iowrite32(min, fifo_mem + SVGA_FIFO_MIN);
+       iowrite32(dev_priv->mmio_size, fifo_mem + SVGA_FIFO_MAX);
+       wmb();
+       iowrite32(min,  fifo_mem + SVGA_FIFO_NEXT_CMD);
+       iowrite32(min,  fifo_mem + SVGA_FIFO_STOP);
+       iowrite32(0, fifo_mem + SVGA_FIFO_BUSY);
+       mb();
+
+       vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1);
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       max = ioread32(fifo_mem + SVGA_FIFO_MAX);
+       min = ioread32(fifo_mem  + SVGA_FIFO_MIN);
+       fifo->capabilities = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES);
+
+       DRM_INFO("Fifo max 0x%08x min 0x%08x cap 0x%08x\n",
+                (unsigned int) max,
+                (unsigned int) min,
+                (unsigned int) fifo->capabilities);
+
+       dev_priv->fence_seq = (uint32_t) -100;
+       dev_priv->last_read_sequence = (uint32_t) -100;
+       iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE);
+
+       return vmw_fifo_send_fence(dev_priv, &dummy);
+out_err:
+       vfree(fifo->static_buffer);
+       fifo->static_buffer = NULL;
+       return ret;
+}
+
+void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+
+       mutex_lock(&dev_priv->hw_mutex);
+
+       if (unlikely(ioread32(fifo_mem + SVGA_FIFO_BUSY) == 0)) {
+               iowrite32(1, fifo_mem + SVGA_FIFO_BUSY);
+               vmw_write(dev_priv, SVGA_REG_SYNC, reason);
+       }
+
+       mutex_unlock(&dev_priv->hw_mutex);
+}
+
+void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+
+       mutex_lock(&dev_priv->hw_mutex);
+
+       while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0)
+               vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
+
+       dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+
+       vmw_write(dev_priv, SVGA_REG_CONFIG_DONE,
+                 dev_priv->config_done_state);
+       vmw_write(dev_priv, SVGA_REG_ENABLE,
+                 dev_priv->enable_state);
+
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       if (likely(fifo->last_buffer != NULL)) {
+               vfree(fifo->last_buffer);
+               fifo->last_buffer = NULL;
+       }
+
+       if (likely(fifo->static_buffer != NULL)) {
+               vfree(fifo->static_buffer);
+               fifo->static_buffer = NULL;
+       }
+
+       if (likely(fifo->dynamic_buffer != NULL)) {
+               vfree(fifo->dynamic_buffer);
+               fifo->dynamic_buffer = NULL;
+       }
+}
+
+static bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX);
+       uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
+       uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
+       uint32_t stop = ioread32(fifo_mem + SVGA_FIFO_STOP);
+
+       return ((max - next_cmd) + (stop - min) <= bytes);
+}
+
+static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv,
+                              uint32_t bytes, bool interruptible,
+                              unsigned long timeout)
+{
+       int ret = 0;
+       unsigned long end_jiffies = jiffies + timeout;
+       DEFINE_WAIT(__wait);
+
+       DRM_INFO("Fifo wait noirq.\n");
+
+       for (;;) {
+               prepare_to_wait(&dev_priv->fifo_queue, &__wait,
+                               (interruptible) ?
+                               TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+               if (!vmw_fifo_is_full(dev_priv, bytes))
+                       break;
+               if (time_after_eq(jiffies, end_jiffies)) {
+                       ret = -EBUSY;
+                       DRM_ERROR("SVGA device lockup.\n");
+                       break;
+               }
+               schedule_timeout(1);
+               if (interruptible && signal_pending(current)) {
+                       ret = -ERESTART;
+                       break;
+               }
+       }
+       finish_wait(&dev_priv->fifo_queue, &__wait);
+       wake_up_all(&dev_priv->fifo_queue);
+       DRM_INFO("Fifo noirq exit.\n");
+       return ret;
+}
+
+static int vmw_fifo_wait(struct vmw_private *dev_priv,
+                        uint32_t bytes, bool interruptible,
+                        unsigned long timeout)
+{
+       long ret = 1L;
+       unsigned long irq_flags;
+
+       if (likely(!vmw_fifo_is_full(dev_priv, bytes)))
+               return 0;
+
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL);
+       if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
+               return vmw_fifo_wait_noirq(dev_priv, bytes,
+                                          interruptible, timeout);
+
+       mutex_lock(&dev_priv->hw_mutex);
+       if (atomic_add_return(1, &dev_priv->fifo_queue_waiters) > 0) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
+               outl(SVGA_IRQFLAG_FIFO_PROGRESS,
+                    dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+               vmw_write(dev_priv, SVGA_REG_IRQMASK,
+                         vmw_read(dev_priv, SVGA_REG_IRQMASK) |
+                         SVGA_IRQFLAG_FIFO_PROGRESS);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
+       }
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       if (interruptible)
+               ret = wait_event_interruptible_timeout
+                   (dev_priv->fifo_queue,
+                    !vmw_fifo_is_full(dev_priv, bytes), timeout);
+       else
+               ret = wait_event_timeout
+                   (dev_priv->fifo_queue,
+                    !vmw_fifo_is_full(dev_priv, bytes), timeout);
+
+       if (unlikely(ret == -ERESTARTSYS))
+               ret = -ERESTART;
+       else if (unlikely(ret == 0))
+               ret = -EBUSY;
+       else if (likely(ret > 0))
+               ret = 0;
+
+       mutex_lock(&dev_priv->hw_mutex);
+       if (atomic_dec_and_test(&dev_priv->fifo_queue_waiters)) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
+               vmw_write(dev_priv, SVGA_REG_IRQMASK,
+                         vmw_read(dev_priv, SVGA_REG_IRQMASK) &
+                         ~SVGA_IRQFLAG_FIFO_PROGRESS);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
+       }
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       return ret;
+}
+
+void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
+{
+       struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       uint32_t max;
+       uint32_t min;
+       uint32_t next_cmd;
+       uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
+       int ret;
+
+       down_write(&fifo_state->rwsem);
+       max = ioread32(fifo_mem + SVGA_FIFO_MAX);
+       min = ioread32(fifo_mem + SVGA_FIFO_MIN);
+       next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
+
+       if (unlikely(bytes >= (max - min)))
+               goto out_err;
+
+       BUG_ON(fifo_state->reserved_size != 0);
+       BUG_ON(fifo_state->dynamic_buffer != NULL);
+
+       fifo_state->reserved_size = bytes;
+
+       while (1) {
+               uint32_t stop = ioread32(fifo_mem + SVGA_FIFO_STOP);
+               bool need_bounce = false;
+               bool reserve_in_place = false;
+
+               if (next_cmd >= stop) {
+                       if (likely((next_cmd + bytes < max ||
+                                   (next_cmd + bytes == max && stop > min))))
+                               reserve_in_place = true;
+
+                       else if (vmw_fifo_is_full(dev_priv, bytes)) {
+                               ret = vmw_fifo_wait(dev_priv, bytes,
+                                                   false, 3 * HZ);
+                               if (unlikely(ret != 0))
+                                       goto out_err;
+                       } else
+                               need_bounce = true;
+
+               } else {
+
+                       if (likely((next_cmd + bytes < stop)))
+                               reserve_in_place = true;
+                       else {
+                               ret = vmw_fifo_wait(dev_priv, bytes,
+                                                   false, 3 * HZ);
+                               if (unlikely(ret != 0))
+                                       goto out_err;
+                       }
+               }
+
+               if (reserve_in_place) {
+                       if (reserveable || bytes <= sizeof(uint32_t)) {
+                               fifo_state->using_bounce_buffer = false;
+
+                               if (reserveable)
+                                       iowrite32(bytes, fifo_mem +
+                                                 SVGA_FIFO_RESERVED);
+                               return fifo_mem + (next_cmd >> 2);
+                       } else {
+                               need_bounce = true;
+                       }
+               }
+
+               if (need_bounce) {
+                       fifo_state->using_bounce_buffer = true;
+                       if (bytes < fifo_state->static_buffer_size)
+                               return fifo_state->static_buffer;
+                       else {
+                               fifo_state->dynamic_buffer = vmalloc(bytes);
+                               return fifo_state->dynamic_buffer;
+                       }
+               }
+       }
+out_err:
+       fifo_state->reserved_size = 0;
+       up_write(&fifo_state->rwsem);
+       return NULL;
+}
+
+static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state,
+                             __le32 __iomem *fifo_mem,
+                             uint32_t next_cmd,
+                             uint32_t max, uint32_t min, uint32_t bytes)
+{
+       uint32_t chunk_size = max - next_cmd;
+       uint32_t rest;
+       uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ?
+           fifo_state->dynamic_buffer : fifo_state->static_buffer;
+
+       if (bytes < chunk_size)
+               chunk_size = bytes;
+
+       iowrite32(bytes, fifo_mem + SVGA_FIFO_RESERVED);
+       mb();
+       memcpy_toio(fifo_mem + (next_cmd >> 2), buffer, chunk_size);
+       rest = bytes - chunk_size;
+       if (rest)
+               memcpy_toio(fifo_mem + (min >> 2), buffer + (chunk_size >> 2),
+                           rest);
+}
+
+static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state,
+                              __le32 __iomem *fifo_mem,
+                              uint32_t next_cmd,
+                              uint32_t max, uint32_t min, uint32_t bytes)
+{
+       uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ?
+           fifo_state->dynamic_buffer : fifo_state->static_buffer;
+
+       while (bytes > 0) {
+               iowrite32(*buffer++, fifo_mem + (next_cmd >> 2));
+               next_cmd += sizeof(uint32_t);
+               if (unlikely(next_cmd == max))
+                       next_cmd = min;
+               mb();
+               iowrite32(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
+               mb();
+               bytes -= sizeof(uint32_t);
+       }
+}
+
+void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
+{
+       struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
+       uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX);
+       uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
+       bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
+
+       BUG_ON((bytes & 3) != 0);
+       BUG_ON(bytes > fifo_state->reserved_size);
+
+       fifo_state->reserved_size = 0;
+
+       if (fifo_state->using_bounce_buffer) {
+               if (reserveable)
+                       vmw_fifo_res_copy(fifo_state, fifo_mem,
+                                         next_cmd, max, min, bytes);
+               else
+                       vmw_fifo_slow_copy(fifo_state, fifo_mem,
+                                          next_cmd, max, min, bytes);
+
+               if (fifo_state->dynamic_buffer) {
+                       vfree(fifo_state->dynamic_buffer);
+                       fifo_state->dynamic_buffer = NULL;
+               }
+
+       }
+
+       if (fifo_state->using_bounce_buffer || reserveable) {
+               next_cmd += bytes;
+               if (next_cmd >= max)
+                       next_cmd -= max - min;
+               mb();
+               iowrite32(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
+       }
+
+       if (reserveable)
+               iowrite32(0, fifo_mem + SVGA_FIFO_RESERVED);
+       mb();
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+       up_write(&fifo_state->rwsem);
+}
+
+int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence)
+{
+       struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
+       struct svga_fifo_cmd_fence *cmd_fence;
+       void *fm;
+       int ret = 0;
+       uint32_t bytes = sizeof(__le32) + sizeof(*cmd_fence);
+
+       fm = vmw_fifo_reserve(dev_priv, bytes);
+       if (unlikely(fm == NULL)) {
+               down_write(&fifo_state->rwsem);
+               *sequence = dev_priv->fence_seq;
+               up_write(&fifo_state->rwsem);
+               ret = -ENOMEM;
+               (void)vmw_fallback_wait(dev_priv, false, true, *sequence,
+                                       false, 3*HZ);
+               goto out_err;
+       }
+
+       do {
+               *sequence = dev_priv->fence_seq++;
+       } while (*sequence == 0);
+
+       if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) {
+
+               /*
+                * Don't request hardware to send a fence. The
+                * waiting code in vmwgfx_irq.c will emulate this.
+                */
+
+               vmw_fifo_commit(dev_priv, 0);
+               return 0;
+       }
+
+       *(__le32 *) fm = cpu_to_le32(SVGA_CMD_FENCE);
+       cmd_fence = (struct svga_fifo_cmd_fence *)
+           ((unsigned long)fm + sizeof(__le32));
+
+       iowrite32(*sequence, &cmd_fence->fence);
+       fifo_state->last_buffer_add = true;
+       vmw_fifo_commit(dev_priv, bytes);
+       fifo_state->last_buffer_add = false;
+
+out_err:
+       return ret;
+}
+
+/**
+ * Map the first page of the FIFO read-only to user-space.
+ */
+
+static int vmw_fifo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       int ret;
+       unsigned long address = (unsigned long)vmf->virtual_address;
+
+       if (address != vma->vm_start)
+               return VM_FAULT_SIGBUS;
+
+       ret = vm_insert_pfn(vma, address, vma->vm_pgoff);
+       if (likely(ret == -EBUSY || ret == 0))
+               return VM_FAULT_NOPAGE;
+       else if (ret == -ENOMEM)
+               return VM_FAULT_OOM;
+
+       return VM_FAULT_SIGBUS;
+}
+
+static struct vm_operations_struct vmw_fifo_vm_ops = {
+       .fault = vmw_fifo_vm_fault,
+       .open = NULL,
+       .close = NULL
+};
+
+int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct vmw_private *dev_priv;
+
+       file_priv = (struct drm_file *)filp->private_data;
+       dev_priv = vmw_priv(file_priv->minor->dev);
+
+       if (vma->vm_pgoff != (dev_priv->mmio_start >> PAGE_SHIFT) ||
+           (vma->vm_end - vma->vm_start) != PAGE_SIZE)
+               return -EINVAL;
+
+       vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+       vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_SHARED;
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       vma->vm_page_prot = ttm_io_prot(TTM_PL_FLAG_UNCACHED,
+                                       vma->vm_page_prot);
+       vma->vm_ops = &vmw_fifo_vm_ops;
+       return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
new file mode 100644 (file)
index 0000000..5f8908a
--- /dev/null
@@ -0,0 +1,213 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "drmP.h"
+#include "ttm/ttm_bo_driver.h"
+
+/**
+ * FIXME: Adjust to the ttm lowmem / highmem storage to minimize
+ * the number of used descriptors.
+ */
+
+static int vmw_gmr_build_descriptors(struct list_head *desc_pages,
+                                    struct page *pages[],
+                                    unsigned long num_pages)
+{
+       struct page *page, *next;
+       struct svga_guest_mem_descriptor *page_virtual = NULL;
+       struct svga_guest_mem_descriptor *desc_virtual = NULL;
+       unsigned int desc_per_page;
+       unsigned long prev_pfn;
+       unsigned long pfn;
+       int ret;
+
+       desc_per_page = PAGE_SIZE /
+           sizeof(struct svga_guest_mem_descriptor) - 1;
+
+       while (likely(num_pages != 0)) {
+               page = alloc_page(__GFP_HIGHMEM);
+               if (unlikely(page == NULL)) {
+                       ret = -ENOMEM;
+                       goto out_err;
+               }
+
+               list_add_tail(&page->lru, desc_pages);
+
+               /*
+                * Point previous page terminating descriptor to this
+                * page before unmapping it.
+                */
+
+               if (likely(page_virtual != NULL)) {
+                       desc_virtual->ppn = page_to_pfn(page);
+                       kunmap_atomic(page_virtual, KM_USER0);
+               }
+
+               page_virtual = kmap_atomic(page, KM_USER0);
+               desc_virtual = page_virtual - 1;
+               prev_pfn = ~(0UL);
+
+               while (likely(num_pages != 0)) {
+                       pfn = page_to_pfn(*pages);
+
+                       if (pfn != prev_pfn + 1) {
+
+                               if (desc_virtual - page_virtual ==
+                                   desc_per_page - 1)
+                                       break;
+
+                               (++desc_virtual)->ppn = cpu_to_le32(pfn);
+                               desc_virtual->num_pages = cpu_to_le32(1);
+                       } else {
+                               uint32_t tmp =
+                                   le32_to_cpu(desc_virtual->num_pages);
+                               desc_virtual->num_pages = cpu_to_le32(tmp + 1);
+                       }
+                       prev_pfn = pfn;
+                       --num_pages;
+                       ++pages;
+               }
+
+               (++desc_virtual)->ppn = cpu_to_le32(0);
+               desc_virtual->num_pages = cpu_to_le32(0);
+       }
+
+       if (likely(page_virtual != NULL))
+               kunmap_atomic(page_virtual, KM_USER0);
+
+       return 0;
+out_err:
+       list_for_each_entry_safe(page, next, desc_pages, lru) {
+               list_del_init(&page->lru);
+               __free_page(page);
+       }
+       return ret;
+}
+
+static inline void vmw_gmr_free_descriptors(struct list_head *desc_pages)
+{
+       struct page *page, *next;
+
+       list_for_each_entry_safe(page, next, desc_pages, lru) {
+               list_del_init(&page->lru);
+               __free_page(page);
+       }
+}
+
+static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv,
+                                    int gmr_id, struct list_head *desc_pages)
+{
+       struct page *page;
+
+       if (unlikely(list_empty(desc_pages)))
+               return;
+
+       page = list_entry(desc_pages->next, struct page, lru);
+
+       mutex_lock(&dev_priv->hw_mutex);
+
+       vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id);
+       wmb();
+       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, page_to_pfn(page));
+       mb();
+
+       mutex_unlock(&dev_priv->hw_mutex);
+
+}
+
+/**
+ * FIXME: Adjust to the ttm lowmem / highmem storage to minimize
+ * the number of used descriptors.
+ */
+
+static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
+                                              unsigned long num_pages)
+{
+       unsigned long prev_pfn = ~(0UL);
+       unsigned long pfn;
+       unsigned long descriptors = 0;
+
+       while (num_pages--) {
+               pfn = page_to_pfn(*pages++);
+               if (prev_pfn + 1 != pfn)
+                       ++descriptors;
+               prev_pfn = pfn;
+       }
+
+       return descriptors;
+}
+
+int vmw_gmr_bind(struct vmw_private *dev_priv,
+                struct ttm_buffer_object *bo)
+{
+       struct ttm_tt *ttm = bo->ttm;
+       unsigned long descriptors;
+       int ret;
+       uint32_t id;
+       struct list_head desc_pages;
+
+       if (!(dev_priv->capabilities & SVGA_CAP_GMR))
+               return -EINVAL;
+
+       ret = ttm_tt_populate(ttm);
+       if (unlikely(ret != 0))
+               return ret;
+
+       descriptors = vmw_gmr_count_descriptors(ttm->pages, ttm->num_pages);
+       if (unlikely(descriptors > dev_priv->max_gmr_descriptors))
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&desc_pages);
+       ret = vmw_gmr_build_descriptors(&desc_pages, ttm->pages,
+                                       ttm->num_pages);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_gmr_id_alloc(dev_priv, &id);
+       if (unlikely(ret != 0))
+               goto out_no_id;
+
+       vmw_gmr_fire_descriptors(dev_priv, id, &desc_pages);
+       vmw_gmr_free_descriptors(&desc_pages);
+       vmw_dmabuf_set_gmr(bo, id);
+       return 0;
+
+out_no_id:
+       vmw_gmr_free_descriptors(&desc_pages);
+       return ret;
+}
+
+void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
+{
+       mutex_lock(&dev_priv->hw_mutex);
+       vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id);
+       wmb();
+       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, 0);
+       mb();
+       mutex_unlock(&dev_priv->hw_mutex);
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
new file mode 100644 (file)
index 0000000..5fa6a4e
--- /dev/null
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "vmwgfx_drm.h"
+
+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;
+
+       switch (param->param) {
+       case DRM_VMW_PARAM_NUM_STREAMS:
+               param->value = vmw_overlay_num_overlays(dev_priv);
+               break;
+       case DRM_VMW_PARAM_NUM_FREE_STREAMS:
+               param->value = vmw_overlay_num_free_overlays(dev_priv);
+               break;
+       case DRM_VMW_PARAM_3D:
+               param->value = dev_priv->capabilities & SVGA_CAP_3D ? 1 : 0;
+               break;
+       case DRM_VMW_PARAM_FIFO_OFFSET:
+               param->value = dev_priv->mmio_start;
+               break;
+       default:
+               DRM_ERROR("Illegal vmwgfx get param request: %d\n",
+                         param->param);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int vmw_fifo_debug_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
+       struct drm_vmw_fifo_debug_arg *arg =
+           (struct drm_vmw_fifo_debug_arg *)data;
+       __le32 __user *buffer = (__le32 __user *)
+           (unsigned long)arg->debug_buffer;
+
+       if (unlikely(fifo_state->last_buffer == NULL))
+               return -EINVAL;
+
+       if (arg->debug_buffer_size < fifo_state->last_data_size) {
+               arg->used_size = arg->debug_buffer_size;
+               arg->did_not_fit = 1;
+       } else {
+               arg->used_size = fifo_state->last_data_size;
+               arg->did_not_fit = 0;
+       }
+       return copy_to_user(buffer, fifo_state->last_buffer, arg->used_size);
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
new file mode 100644 (file)
index 0000000..9e0f030
--- /dev/null
@@ -0,0 +1,295 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+#define VMW_FENCE_WRAP (1 << 24)
+
+irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       uint32_t status;
+
+       spin_lock(&dev_priv->irq_lock);
+       status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+       spin_unlock(&dev_priv->irq_lock);
+
+       if (status & SVGA_IRQFLAG_ANY_FENCE)
+               wake_up_all(&dev_priv->fence_queue);
+       if (status & SVGA_IRQFLAG_FIFO_PROGRESS)
+               wake_up_all(&dev_priv->fifo_queue);
+
+       if (likely(status)) {
+               outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence)
+{
+       uint32_t busy;
+
+       mutex_lock(&dev_priv->hw_mutex);
+       busy = vmw_read(dev_priv, SVGA_REG_BUSY);
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       return (busy == 0);
+}
+
+
+bool vmw_fence_signaled(struct vmw_private *dev_priv,
+                       uint32_t sequence)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       struct vmw_fifo_state *fifo_state;
+       bool ret;
+
+       if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP))
+               return true;
+
+       dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+       if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP))
+               return true;
+
+       fifo_state = &dev_priv->fifo;
+       if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) &&
+           vmw_fifo_idle(dev_priv, sequence))
+               return true;
+
+       /**
+        * Below is to signal stale fences that have wrapped.
+        * First, block fence submission.
+        */
+
+       down_read(&fifo_state->rwsem);
+
+       /**
+        * Then check if the sequence is higher than what we've actually
+        * emitted. Then the fence is stale and signaled.
+        */
+
+       ret = ((dev_priv->fence_seq - sequence) > VMW_FENCE_WRAP);
+       up_read(&fifo_state->rwsem);
+
+       return ret;
+}
+
+int vmw_fallback_wait(struct vmw_private *dev_priv,
+                     bool lazy,
+                     bool fifo_idle,
+                     uint32_t sequence,
+                     bool interruptible,
+                     unsigned long timeout)
+{
+       struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
+
+       uint32_t count = 0;
+       uint32_t signal_seq;
+       int ret;
+       unsigned long end_jiffies = jiffies + timeout;
+       bool (*wait_condition)(struct vmw_private *, uint32_t);
+       DEFINE_WAIT(__wait);
+
+       wait_condition = (fifo_idle) ? &vmw_fifo_idle :
+               &vmw_fence_signaled;
+
+       /**
+        * Block command submission while waiting for idle.
+        */
+
+       if (fifo_idle)
+               down_read(&fifo_state->rwsem);
+       signal_seq = dev_priv->fence_seq;
+       ret = 0;
+
+       for (;;) {
+               prepare_to_wait(&dev_priv->fence_queue, &__wait,
+                               (interruptible) ?
+                               TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+               if (wait_condition(dev_priv, sequence))
+                       break;
+               if (time_after_eq(jiffies, end_jiffies)) {
+                       DRM_ERROR("SVGA device lockup.\n");
+                       break;
+               }
+               if (lazy)
+                       schedule_timeout(1);
+               else if ((++count & 0x0F) == 0) {
+                       /**
+                        * FIXME: Use schedule_hr_timeout here for
+                        * newer kernels and lower CPU utilization.
+                        */
+
+                       __set_current_state(TASK_RUNNING);
+                       schedule();
+                       __set_current_state((interruptible) ?
+                                           TASK_INTERRUPTIBLE :
+                                           TASK_UNINTERRUPTIBLE);
+               }
+               if (interruptible && signal_pending(current)) {
+                       ret = -ERESTART;
+                       break;
+               }
+       }
+       finish_wait(&dev_priv->fence_queue, &__wait);
+       if (ret == 0 && fifo_idle) {
+               __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+               iowrite32(signal_seq, fifo_mem + SVGA_FIFO_FENCE);
+       }
+       wake_up_all(&dev_priv->fence_queue);
+       if (fifo_idle)
+               up_read(&fifo_state->rwsem);
+
+       return ret;
+}
+
+int vmw_wait_fence(struct vmw_private *dev_priv,
+                  bool lazy, uint32_t sequence,
+                  bool interruptible, unsigned long timeout)
+{
+       long ret;
+       unsigned long irq_flags;
+       struct vmw_fifo_state *fifo = &dev_priv->fifo;
+
+       if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP))
+               return 0;
+
+       if (likely(vmw_fence_signaled(dev_priv, sequence)))
+               return 0;
+
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+
+       if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE))
+               return vmw_fallback_wait(dev_priv, lazy, true, sequence,
+                                        interruptible, timeout);
+
+       if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
+               return vmw_fallback_wait(dev_priv, lazy, false, sequence,
+                                        interruptible, timeout);
+
+       mutex_lock(&dev_priv->hw_mutex);
+       if (atomic_add_return(1, &dev_priv->fence_queue_waiters) > 0) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
+               outl(SVGA_IRQFLAG_ANY_FENCE,
+                    dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+               vmw_write(dev_priv, SVGA_REG_IRQMASK,
+                         vmw_read(dev_priv, SVGA_REG_IRQMASK) |
+                         SVGA_IRQFLAG_ANY_FENCE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
+       }
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       if (interruptible)
+               ret = wait_event_interruptible_timeout
+                   (dev_priv->fence_queue,
+                    vmw_fence_signaled(dev_priv, sequence),
+                    timeout);
+       else
+               ret = wait_event_timeout
+                   (dev_priv->fence_queue,
+                    vmw_fence_signaled(dev_priv, sequence),
+                    timeout);
+
+       if (unlikely(ret == -ERESTARTSYS))
+               ret = -ERESTART;
+       else if (unlikely(ret == 0))
+               ret = -EBUSY;
+       else if (likely(ret > 0))
+               ret = 0;
+
+       mutex_lock(&dev_priv->hw_mutex);
+       if (atomic_dec_and_test(&dev_priv->fence_queue_waiters)) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
+               vmw_write(dev_priv, SVGA_REG_IRQMASK,
+                         vmw_read(dev_priv, SVGA_REG_IRQMASK) &
+                         ~SVGA_IRQFLAG_ANY_FENCE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
+       }
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       return ret;
+}
+
+void vmw_irq_preinstall(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       uint32_t status;
+
+       if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
+               return;
+
+       spin_lock_init(&dev_priv->irq_lock);
+       status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+       outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+}
+
+int vmw_irq_postinstall(struct drm_device *dev)
+{
+       return 0;
+}
+
+void vmw_irq_uninstall(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       uint32_t status;
+
+       if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
+               return;
+
+       mutex_lock(&dev_priv->hw_mutex);
+       vmw_write(dev_priv, SVGA_REG_IRQMASK, 0);
+       mutex_unlock(&dev_priv->hw_mutex);
+
+       status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+       outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+}
+
+#define VMW_FENCE_WAIT_TIMEOUT 3*HZ;
+
+int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_vmw_fence_wait_arg *arg =
+           (struct drm_vmw_fence_wait_arg *)data;
+       unsigned long timeout;
+
+       if (!arg->cookie_valid) {
+               arg->cookie_valid = 1;
+               arg->kernel_cookie = jiffies + VMW_FENCE_WAIT_TIMEOUT;
+       }
+
+       timeout = jiffies;
+       if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie))
+               return -EBUSY;
+
+       timeout = (unsigned long)arg->kernel_cookie - timeout;
+       return vmw_wait_fence(vmw_priv(dev), true, arg->sequence, true, timeout);
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
new file mode 100644 (file)
index 0000000..e9403be
--- /dev/null
@@ -0,0 +1,872 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_kms.h"
+
+/* Might need a hrtimer here? */
+#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
+
+
+void vmw_display_unit_cleanup(struct vmw_display_unit *du)
+{
+       if (du->cursor_surface)
+               vmw_surface_unreference(&du->cursor_surface);
+       if (du->cursor_dmabuf)
+               vmw_dmabuf_unreference(&du->cursor_dmabuf);
+       drm_crtc_cleanup(&du->crtc);
+       drm_encoder_cleanup(&du->encoder);
+       drm_connector_cleanup(&du->connector);
+}
+
+/*
+ * Display Unit Cursor functions
+ */
+
+int vmw_cursor_update_image(struct vmw_private *dev_priv,
+                           u32 *image, u32 width, u32 height,
+                           u32 hotspotX, u32 hotspotY)
+{
+       struct {
+               u32 cmd;
+               SVGAFifoCmdDefineAlphaCursor cursor;
+       } *cmd;
+       u32 image_size = width * height * 4;
+       u32 cmd_size = sizeof(*cmd) + image_size;
+
+       if (!image)
+               return -EINVAL;
+
+       cmd = vmw_fifo_reserve(dev_priv, cmd_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               return -ENOMEM;
+       }
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       memcpy(&cmd[1], image, image_size);
+
+       cmd->cmd = cpu_to_le32(SVGA_CMD_DEFINE_ALPHA_CURSOR);
+       cmd->cursor.id = cpu_to_le32(0);
+       cmd->cursor.width = cpu_to_le32(width);
+       cmd->cursor.height = cpu_to_le32(height);
+       cmd->cursor.hotspotX = cpu_to_le32(hotspotX);
+       cmd->cursor.hotspotY = cpu_to_le32(hotspotY);
+
+       vmw_fifo_commit(dev_priv, cmd_size);
+
+       return 0;
+}
+
+void vmw_cursor_update_position(struct vmw_private *dev_priv,
+                               bool show, int x, int y)
+{
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       uint32_t count;
+
+       iowrite32(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON);
+       iowrite32(x, fifo_mem + SVGA_FIFO_CURSOR_X);
+       iowrite32(y, fifo_mem + SVGA_FIFO_CURSOR_Y);
+       count = ioread32(fifo_mem + SVGA_FIFO_CURSOR_COUNT);
+       iowrite32(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT);
+}
+
+int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
+                          uint32_t handle, uint32_t width, uint32_t height)
+{
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
+       struct vmw_surface *surface = NULL;
+       struct vmw_dma_buffer *dmabuf = NULL;
+       int ret;
+
+       if (handle) {
+               ret = vmw_user_surface_lookup(dev_priv, tfile,
+                                             handle, &surface);
+               if (!ret) {
+                       if (!surface->snooper.image) {
+                               DRM_ERROR("surface not suitable for cursor\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       ret = vmw_user_dmabuf_lookup(tfile,
+                                                    handle, &dmabuf);
+                       if (ret) {
+                               DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       /* takedown old cursor */
+       if (du->cursor_surface) {
+               du->cursor_surface->snooper.crtc = NULL;
+               vmw_surface_unreference(&du->cursor_surface);
+       }
+       if (du->cursor_dmabuf)
+               vmw_dmabuf_unreference(&du->cursor_dmabuf);
+
+       /* setup new image */
+       if (surface) {
+               /* vmw_user_surface_lookup takes one reference */
+               du->cursor_surface = surface;
+
+               du->cursor_surface->snooper.crtc = crtc;
+               du->cursor_age = du->cursor_surface->snooper.age;
+               vmw_cursor_update_image(dev_priv, surface->snooper.image,
+                                       64, 64, du->hotspot_x, du->hotspot_y);
+       } else if (dmabuf) {
+               struct ttm_bo_kmap_obj map;
+               unsigned long kmap_offset;
+               unsigned long kmap_num;
+               void *virtual;
+               bool dummy;
+
+               /* vmw_user_surface_lookup takes one reference */
+               du->cursor_dmabuf = dmabuf;
+
+               kmap_offset = 0;
+               kmap_num = (64*64*4) >> PAGE_SHIFT;
+
+               ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("reserve failed\n");
+                       return -EINVAL;
+               }
+
+               ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map);
+               if (unlikely(ret != 0))
+                       goto err_unreserve;
+
+               virtual = ttm_kmap_obj_virtual(&map, &dummy);
+               vmw_cursor_update_image(dev_priv, virtual, 64, 64,
+                                       du->hotspot_x, du->hotspot_y);
+
+               ttm_bo_kunmap(&map);
+err_unreserve:
+               ttm_bo_unreserve(&dmabuf->base);
+
+       } else {
+               vmw_cursor_update_position(dev_priv, false, 0, 0);
+               return 0;
+       }
+
+       vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y);
+
+       return 0;
+}
+
+int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+       struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
+       bool shown = du->cursor_surface || du->cursor_dmabuf ? true : false;
+
+       du->cursor_x = x + crtc->x;
+       du->cursor_y = y + crtc->y;
+
+       vmw_cursor_update_position(dev_priv, shown,
+                                  du->cursor_x, du->cursor_y);
+
+       return 0;
+}
+
+void vmw_kms_cursor_snoop(struct vmw_surface *srf,
+                         struct ttm_object_file *tfile,
+                         struct ttm_buffer_object *bo,
+                         SVGA3dCmdHeader *header)
+{
+       struct ttm_bo_kmap_obj map;
+       unsigned long kmap_offset;
+       unsigned long kmap_num;
+       SVGA3dCopyBox *box;
+       unsigned box_count;
+       void *virtual;
+       bool dummy;
+       struct vmw_dma_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSurfaceDMA dma;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_dma_cmd, header);
+
+       /* No snooper installed */
+       if (!srf->snooper.image)
+               return;
+
+       if (cmd->dma.host.face != 0 || cmd->dma.host.mipmap != 0) {
+               DRM_ERROR("face and mipmap for cursors should never != 0\n");
+               return;
+       }
+
+       if (cmd->header.size < 64) {
+               DRM_ERROR("at least one full copy box must be given\n");
+               return;
+       }
+
+       box = (SVGA3dCopyBox *)&cmd[1];
+       box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) /
+                       sizeof(SVGA3dCopyBox);
+
+       if (cmd->dma.guest.pitch != (64 * 4) ||
+           cmd->dma.guest.ptr.offset % PAGE_SIZE ||
+           box->x != 0    || box->y != 0    || box->z != 0    ||
+           box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
+           box->w != 64   || box->h != 64   || box->d != 1    ||
+           box_count != 1) {
+               /* TODO handle none page aligned offsets */
+               /* TODO handle partial uploads and pitch != 256 */
+               /* TODO handle more then one copy (size != 64) */
+               DRM_ERROR("lazy programer, cant handle wierd stuff\n");
+               return;
+       }
+
+       kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
+       kmap_num = (64*64*4) >> PAGE_SHIFT;
+
+       ret = ttm_bo_reserve(bo, true, false, false, 0);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("reserve failed\n");
+               return;
+       }
+
+       ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map);
+       if (unlikely(ret != 0))
+               goto err_unreserve;
+
+       virtual = ttm_kmap_obj_virtual(&map, &dummy);
+
+       memcpy(srf->snooper.image, virtual, 64*64*4);
+       srf->snooper.age++;
+
+       /* we can't call this function from this function since execbuf has
+        * reserved fifo space.
+        *
+        * if (srf->snooper.crtc)
+        *      vmw_ldu_crtc_cursor_update_image(dev_priv,
+        *                                       srf->snooper.image, 64, 64,
+        *                                       du->hotspot_x, du->hotspot_y);
+        */
+
+       ttm_bo_kunmap(&map);
+err_unreserve:
+       ttm_bo_unreserve(bo);
+}
+
+void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct vmw_display_unit *du;
+       struct drm_crtc *crtc;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               du = vmw_crtc_to_du(crtc);
+               if (!du->cursor_surface ||
+                   du->cursor_age == du->cursor_surface->snooper.age)
+                       continue;
+
+               du->cursor_age = du->cursor_surface->snooper.age;
+               vmw_cursor_update_image(dev_priv,
+                                       du->cursor_surface->snooper.image,
+                                       64, 64, du->hotspot_x, du->hotspot_y);
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+/*
+ * Generic framebuffer code
+ */
+
+int vmw_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                 struct drm_file *file_priv,
+                                 unsigned int *handle)
+{
+       if (handle)
+               handle = 0;
+
+       return 0;
+}
+
+/*
+ * Surface framebuffer code
+ */
+
+#define vmw_framebuffer_to_vfbs(x) \
+       container_of(x, struct vmw_framebuffer_surface, base.base)
+
+struct vmw_framebuffer_surface {
+       struct vmw_framebuffer base;
+       struct vmw_surface *surface;
+       struct delayed_work d_work;
+       struct mutex work_lock;
+       bool present_fs;
+};
+
+void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
+{
+       struct vmw_framebuffer_surface *vfb =
+               vmw_framebuffer_to_vfbs(framebuffer);
+
+       cancel_delayed_work_sync(&vfb->d_work);
+       drm_framebuffer_cleanup(framebuffer);
+       vmw_surface_unreference(&vfb->surface);
+
+       kfree(framebuffer);
+}
+
+static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
+{
+       struct delayed_work *d_work =
+               container_of(work, struct delayed_work, work);
+       struct vmw_framebuffer_surface *vfbs =
+               container_of(d_work, struct vmw_framebuffer_surface, d_work);
+       struct vmw_surface *surf = vfbs->surface;
+       struct drm_framebuffer *framebuffer = &vfbs->base.base;
+       struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdPresent body;
+               SVGA3dCopyRect cr;
+       } *cmd;
+
+       mutex_lock(&vfbs->work_lock);
+       if (!vfbs->present_fs)
+               goto out_unlock;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL))
+               goto out_resched;
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_PRESENT);
+       cmd->header.size = cpu_to_le32(sizeof(cmd->body) + sizeof(cmd->cr));
+       cmd->body.sid = cpu_to_le32(surf->res.id);
+       cmd->cr.x = cpu_to_le32(0);
+       cmd->cr.y = cpu_to_le32(0);
+       cmd->cr.srcx = cmd->cr.x;
+       cmd->cr.srcy = cmd->cr.y;
+       cmd->cr.w = cpu_to_le32(framebuffer->width);
+       cmd->cr.h = cpu_to_le32(framebuffer->height);
+       vfbs->present_fs = false;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+out_resched:
+       /**
+        * Will not re-add if already pending.
+        */
+       schedule_delayed_work(&vfbs->d_work, VMWGFX_PRESENT_RATE);
+out_unlock:
+       mutex_unlock(&vfbs->work_lock);
+}
+
+
+int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+                                 unsigned flags, unsigned color,
+                                 struct drm_clip_rect *clips,
+                                 unsigned num_clips)
+{
+       struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct vmw_framebuffer_surface *vfbs =
+               vmw_framebuffer_to_vfbs(framebuffer);
+       struct vmw_surface *surf = vfbs->surface;
+       struct drm_clip_rect norect;
+       SVGA3dCopyRect *cr;
+       int i, inc = 1;
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdPresent body;
+               SVGA3dCopyRect cr;
+       } *cmd;
+
+       if (!num_clips ||
+           !(dev_priv->fifo.capabilities &
+             SVGA_FIFO_CAP_SCREEN_OBJECT)) {
+               int ret;
+
+               mutex_lock(&vfbs->work_lock);
+               vfbs->present_fs = true;
+               ret = schedule_delayed_work(&vfbs->d_work, VMWGFX_PRESENT_RATE);
+               mutex_unlock(&vfbs->work_lock);
+               if (ret) {
+                       /**
+                        * No work pending, Force immediate present.
+                        */
+                       vmw_framebuffer_present_fs_callback(&vfbs->d_work.work);
+               }
+               return 0;
+       }
+
+       if (!num_clips) {
+               num_clips = 1;
+               clips = &norect;
+               norect.x1 = norect.y1 = 0;
+               norect.x2 = framebuffer->width;
+               norect.y2 = framebuffer->height;
+       } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
+               num_clips /= 2;
+               inc = 2; /* skip source rects */
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               return -ENOMEM;
+       }
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_PRESENT);
+       cmd->header.size = cpu_to_le32(sizeof(cmd->body) + num_clips * sizeof(cmd->cr));
+       cmd->body.sid = cpu_to_le32(surf->res.id);
+
+       for (i = 0, cr = &cmd->cr; i < num_clips; i++, cr++, clips += inc) {
+               cr->x = cpu_to_le16(clips->x1);
+               cr->y = cpu_to_le16(clips->y1);
+               cr->srcx = cr->x;
+               cr->srcy = cr->y;
+               cr->w = cpu_to_le16(clips->x2 - clips->x1);
+               cr->h = cpu_to_le16(clips->y2 - clips->y1);
+       }
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
+
+       return 0;
+}
+
+static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
+       .destroy = vmw_framebuffer_surface_destroy,
+       .dirty = vmw_framebuffer_surface_dirty,
+       .create_handle = vmw_framebuffer_create_handle,
+};
+
+int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
+                                   struct vmw_surface *surface,
+                                   struct vmw_framebuffer **out,
+                                   unsigned width, unsigned height)
+
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct vmw_framebuffer_surface *vfbs;
+       int ret;
+
+       vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
+       if (!vfbs) {
+               ret = -ENOMEM;
+               goto out_err1;
+       }
+
+       ret = drm_framebuffer_init(dev, &vfbs->base.base,
+                                  &vmw_framebuffer_surface_funcs);
+       if (ret)
+               goto out_err2;
+
+       if (!vmw_surface_reference(surface)) {
+               DRM_ERROR("failed to reference surface %p\n", surface);
+               goto out_err3;
+       }
+
+       /* XXX get the first 3 from the surface info */
+       vfbs->base.base.bits_per_pixel = 32;
+       vfbs->base.base.pitch = width * 32 / 4;
+       vfbs->base.base.depth = 24;
+       vfbs->base.base.width = width;
+       vfbs->base.base.height = height;
+       vfbs->base.pin = NULL;
+       vfbs->base.unpin = NULL;
+       vfbs->surface = surface;
+       mutex_init(&vfbs->work_lock);
+       INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
+       *out = &vfbs->base;
+
+       return 0;
+
+out_err3:
+       drm_framebuffer_cleanup(&vfbs->base.base);
+out_err2:
+       kfree(vfbs);
+out_err1:
+       return ret;
+}
+
+/*
+ * Dmabuf framebuffer code
+ */
+
+#define vmw_framebuffer_to_vfbd(x) \
+       container_of(x, struct vmw_framebuffer_dmabuf, base.base)
+
+struct vmw_framebuffer_dmabuf {
+       struct vmw_framebuffer base;
+       struct vmw_dma_buffer *buffer;
+};
+
+void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
+{
+       struct vmw_framebuffer_dmabuf *vfbd =
+               vmw_framebuffer_to_vfbd(framebuffer);
+
+       drm_framebuffer_cleanup(framebuffer);
+       vmw_dmabuf_unreference(&vfbd->buffer);
+
+       kfree(vfbd);
+}
+
+int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+                                unsigned flags, unsigned color,
+                                struct drm_clip_rect *clips,
+                                unsigned num_clips)
+{
+       struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct drm_clip_rect norect;
+       struct {
+               uint32_t header;
+               SVGAFifoCmdUpdate body;
+       } *cmd;
+       int i, increment = 1;
+
+       if (!num_clips ||
+           !(dev_priv->fifo.capabilities &
+             SVGA_FIFO_CAP_SCREEN_OBJECT)) {
+               num_clips = 1;
+               clips = &norect;
+               norect.x1 = norect.y1 = 0;
+               norect.x2 = framebuffer->width;
+               norect.y2 = framebuffer->height;
+       } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
+               num_clips /= 2;
+               increment = 2;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < num_clips; i++, clips += increment) {
+               cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
+               cmd[i].body.x = cpu_to_le32(clips[i].x1);
+               cmd[i].body.y = cpu_to_le32(clips[i].y1);
+               cmd[i].body.width = cpu_to_le32(clips[i].x2 - clips[i].x1);
+               cmd[i].body.height = cpu_to_le32(clips[i].y2 - clips[i].y1);
+       }
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
+
+       return 0;
+}
+
+static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
+       .destroy = vmw_framebuffer_dmabuf_destroy,
+       .dirty = vmw_framebuffer_dmabuf_dirty,
+       .create_handle = vmw_framebuffer_create_handle,
+};
+
+static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
+{
+       struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
+       struct vmw_framebuffer_dmabuf *vfbd =
+               vmw_framebuffer_to_vfbd(&vfb->base);
+       int ret;
+
+       vmw_overlay_pause_all(dev_priv);
+
+       ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer);
+
+       if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
+               vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+
+               vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
+               vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width);
+               vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height);
+               vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel);
+               vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth);
+               vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000);
+               vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
+               vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
+       } else
+               WARN_ON(true);
+
+       vmw_overlay_resume_all(dev_priv);
+
+       return 0;
+}
+
+static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
+{
+       struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
+       struct vmw_framebuffer_dmabuf *vfbd =
+               vmw_framebuffer_to_vfbd(&vfb->base);
+
+       if (!vfbd->buffer) {
+               WARN_ON(!vfbd->buffer);
+               return 0;
+       }
+
+       return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
+}
+
+int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
+                                  struct vmw_dma_buffer *dmabuf,
+                                  struct vmw_framebuffer **out,
+                                  unsigned width, unsigned height)
+
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct vmw_framebuffer_dmabuf *vfbd;
+       int ret;
+
+       vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
+       if (!vfbd) {
+               ret = -ENOMEM;
+               goto out_err1;
+       }
+
+       ret = drm_framebuffer_init(dev, &vfbd->base.base,
+                                  &vmw_framebuffer_dmabuf_funcs);
+       if (ret)
+               goto out_err2;
+
+       if (!vmw_dmabuf_reference(dmabuf)) {
+               DRM_ERROR("failed to reference dmabuf %p\n", dmabuf);
+               goto out_err3;
+       }
+
+       /* XXX get the first 3 from the surface info */
+       vfbd->base.base.bits_per_pixel = 32;
+       vfbd->base.base.pitch = width * 32 / 4;
+       vfbd->base.base.depth = 24;
+       vfbd->base.base.width = width;
+       vfbd->base.base.height = height;
+       vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
+       vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
+       vfbd->buffer = dmabuf;
+       *out = &vfbd->base;
+
+       return 0;
+
+out_err3:
+       drm_framebuffer_cleanup(&vfbd->base.base);
+out_err2:
+       kfree(vfbd);
+out_err1:
+       return ret;
+}
+
+/*
+ * Generic Kernel modesetting functions
+ */
+
+static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
+                                                struct drm_file *file_priv,
+                                                struct drm_mode_fb_cmd *mode_cmd)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_framebuffer *vfb = NULL;
+       struct vmw_surface *surface = NULL;
+       struct vmw_dma_buffer *bo = NULL;
+       int ret;
+
+       ret = vmw_user_surface_lookup(dev_priv, tfile,
+                                     mode_cmd->handle, &surface);
+       if (ret)
+               goto try_dmabuf;
+
+       ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
+                                             mode_cmd->width, mode_cmd->height);
+
+       /* vmw_user_surface_lookup takes one ref so does new_fb */
+       vmw_surface_unreference(&surface);
+
+       if (ret) {
+               DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
+               return NULL;
+       }
+       return &vfb->base;
+
+try_dmabuf:
+       DRM_INFO("%s: trying buffer\n", __func__);
+
+       ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo);
+       if (ret) {
+               DRM_ERROR("failed to find buffer: %i\n", ret);
+               return NULL;
+       }
+
+       ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
+                                            mode_cmd->width, mode_cmd->height);
+
+       /* vmw_user_dmabuf_lookup takes one ref so does new_fb */
+       vmw_dmabuf_unreference(&bo);
+
+       if (ret) {
+               DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
+               return NULL;
+       }
+
+       return &vfb->base;
+}
+
+static int vmw_kms_fb_changed(struct drm_device *dev)
+{
+       return 0;
+}
+
+static struct drm_mode_config_funcs vmw_kms_funcs = {
+       .fb_create = vmw_kms_fb_create,
+       .fb_changed = vmw_kms_fb_changed,
+};
+
+int vmw_kms_init(struct vmw_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
+
+       drm_mode_config_init(dev);
+       dev->mode_config.funcs = &vmw_kms_funcs;
+       dev->mode_config.min_width = 640;
+       dev->mode_config.min_height = 480;
+       dev->mode_config.max_width = 2048;
+       dev->mode_config.max_height = 2048;
+
+       ret = vmw_kms_init_legacy_display_system(dev_priv);
+
+       return 0;
+}
+
+int vmw_kms_close(struct vmw_private *dev_priv)
+{
+       /*
+        * Docs says we should take the lock before calling this function
+        * but since it destroys encoders and our destructor calls
+        * drm_encoder_cleanup which takes the lock we deadlock.
+        */
+       drm_mode_config_cleanup(dev_priv->dev);
+       vmw_kms_close_legacy_display_system(dev_priv);
+       return 0;
+}
+
+int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct drm_vmw_cursor_bypass_arg *arg = data;
+       struct vmw_display_unit *du;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+
+       mutex_lock(&dev->mode_config.mutex);
+       if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) {
+
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+                       du = vmw_crtc_to_du(crtc);
+                       du->hotspot_x = arg->xhot;
+                       du->hotspot_y = arg->yhot;
+               }
+
+               mutex_unlock(&dev->mode_config.mutex);
+               return 0;
+       }
+
+       obj = drm_mode_object_find(dev, arg->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       crtc = obj_to_crtc(obj);
+       du = vmw_crtc_to_du(crtc);
+
+       du->hotspot_x = arg->xhot;
+       du->hotspot_y = arg->yhot;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+int vmw_kms_save_vga(struct vmw_private *vmw_priv)
+{
+       /*
+        * setup a single multimon monitor with the size
+        * of 0x0, this stops the UI from resizing when we
+        * change the framebuffer size
+        */
+       if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
+               vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
+               vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+       }
+
+       vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH);
+       vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT);
+       vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL);
+       vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH);
+       vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR);
+       vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK);
+       vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK);
+       vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK);
+
+       return 0;
+}
+
+int vmw_kms_restore_vga(struct vmw_private *vmw_priv)
+{
+       vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width);
+       vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height);
+       vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp);
+       vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth);
+       vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo);
+       vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask);
+       vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask);
+       vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask);
+
+       /* TODO check for multimon */
+       vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
new file mode 100644 (file)
index 0000000..8b95249
--- /dev/null
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef VMWGFX_KMS_H_
+#define VMWGFX_KMS_H_
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+
+#define vmw_framebuffer_to_vfb(x) \
+       container_of(x, struct vmw_framebuffer, base)
+
+/**
+ * Base class for framebuffers
+ *
+ * @pin is called the when ever a crtc uses this framebuffer
+ * @unpin is called
+ */
+struct vmw_framebuffer {
+       struct drm_framebuffer base;
+       int (*pin)(struct vmw_framebuffer *fb);
+       int (*unpin)(struct vmw_framebuffer *fb);
+};
+
+
+#define vmw_crtc_to_du(x) \
+       container_of(x, struct vmw_display_unit, crtc)
+
+/*
+ * Basic cursor manipulation
+ */
+int vmw_cursor_update_image(struct vmw_private *dev_priv,
+                           u32 *image, u32 width, u32 height,
+                           u32 hotspotX, u32 hotspotY);
+void vmw_cursor_update_position(struct vmw_private *dev_priv,
+                               bool show, int x, int y);
+
+/**
+ * Base class display unit.
+ *
+ * Since the SVGA hw doesn't have a concept of a crtc, encoder or connector
+ * so the display unit is all of them at the same time. This is true for both
+ * legacy multimon and screen objects.
+ */
+struct vmw_display_unit {
+       struct drm_crtc crtc;
+       struct drm_encoder encoder;
+       struct drm_connector connector;
+
+       struct vmw_surface *cursor_surface;
+       struct vmw_dma_buffer *cursor_dmabuf;
+       size_t cursor_age;
+
+       int cursor_x;
+       int cursor_y;
+
+       int hotspot_x;
+       int hotspot_y;
+
+       unsigned unit;
+};
+
+/*
+ * Shared display unit functions - vmwgfx_kms.c
+ */
+void vmw_display_unit_cleanup(struct vmw_display_unit *du);
+int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
+                          uint32_t handle, uint32_t width, uint32_t height);
+int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
+
+/*
+ * Legacy display unit functions - vmwgfx_ldu.h
+ */
+int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv);
+int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv);
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
new file mode 100644 (file)
index 0000000..9089159
--- /dev/null
@@ -0,0 +1,516 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_kms.h"
+
+#define vmw_crtc_to_ldu(x) \
+       container_of(x, struct vmw_legacy_display_unit, base.crtc)
+#define vmw_encoder_to_ldu(x) \
+       container_of(x, struct vmw_legacy_display_unit, base.encoder)
+#define vmw_connector_to_ldu(x) \
+       container_of(x, struct vmw_legacy_display_unit, base.connector)
+
+struct vmw_legacy_display {
+       struct list_head active;
+
+       unsigned num_active;
+
+       struct vmw_framebuffer *fb;
+};
+
+/**
+ * Display unit using the legacy register interface.
+ */
+struct vmw_legacy_display_unit {
+       struct vmw_display_unit base;
+
+       struct list_head active;
+
+       unsigned unit;
+};
+
+static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
+{
+       list_del_init(&ldu->active);
+       vmw_display_unit_cleanup(&ldu->base);
+       kfree(ldu);
+}
+
+
+/*
+ * Legacy Display Unit CRTC functions
+ */
+
+static void vmw_ldu_crtc_save(struct drm_crtc *crtc)
+{
+}
+
+static void vmw_ldu_crtc_restore(struct drm_crtc *crtc)
+{
+}
+
+static void vmw_ldu_crtc_gamma_set(struct drm_crtc *crtc,
+                                  u16 *r, u16 *g, u16 *b,
+                                  uint32_t size)
+{
+}
+
+static void vmw_ldu_crtc_destroy(struct drm_crtc *crtc)
+{
+       vmw_ldu_destroy(vmw_crtc_to_ldu(crtc));
+}
+
+static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
+{
+       struct vmw_legacy_display *lds = dev_priv->ldu_priv;
+       struct vmw_legacy_display_unit *entry;
+       struct drm_crtc *crtc;
+       int i = 0;
+
+       /* to stop the screen from changing size on resize */
+       vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0);
+       for (i = 0; i < lds->num_active; i++) {
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+       }
+
+       /* Now set the mode */
+       vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active);
+       i = 0;
+       list_for_each_entry(entry, &lds->active, active) {
+               crtc = &entry->base.crtc;
+
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, crtc->x);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, crtc->y);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, crtc->mode.hdisplay);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, crtc->mode.vdisplay);
+               vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+
+               i++;
+       }
+
+       return 0;
+}
+
+static int vmw_ldu_del_active(struct vmw_private *vmw_priv,
+                             struct vmw_legacy_display_unit *ldu)
+{
+       struct vmw_legacy_display *ld = vmw_priv->ldu_priv;
+       if (list_empty(&ldu->active))
+               return 0;
+
+       list_del_init(&ldu->active);
+       if (--(ld->num_active) == 0) {
+               BUG_ON(!ld->fb);
+               if (ld->fb->unpin)
+                       ld->fb->unpin(ld->fb);
+               ld->fb = NULL;
+       }
+
+       return 0;
+}
+
+static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
+                             struct vmw_legacy_display_unit *ldu,
+                             struct vmw_framebuffer *vfb)
+{
+       struct vmw_legacy_display *ld = vmw_priv->ldu_priv;
+       struct vmw_legacy_display_unit *entry;
+       struct list_head *at;
+
+       if (!list_empty(&ldu->active))
+               return 0;
+
+       at = &ld->active;
+       list_for_each_entry(entry, &ld->active, active) {
+               if (entry->unit > ldu->unit)
+                       break;
+
+               at = &entry->active;
+       }
+
+       list_add(&ldu->active, at);
+       if (ld->num_active++ == 0) {
+               BUG_ON(ld->fb);
+               if (vfb->pin)
+                       vfb->pin(vfb);
+               ld->fb = vfb;
+       }
+
+       return 0;
+}
+
+static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_legacy_display_unit *ldu;
+       struct drm_connector *connector;
+       struct drm_display_mode *mode;
+       struct drm_encoder *encoder;
+       struct vmw_framebuffer *vfb;
+       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
+
+       if (!set)
+               return -EINVAL;
+
+       if (!set->crtc)
+               return -EINVAL;
+
+       /* get the ldu */
+       crtc = set->crtc;
+       ldu = vmw_crtc_to_ldu(crtc);
+       vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
+       dev_priv = vmw_priv(crtc->dev);
+
+       if (set->num_connectors > 1) {
+               DRM_ERROR("to many connectors\n");
+               return -EINVAL;
+       }
+
+       if (set->num_connectors == 1 &&
+           set->connectors[0] != &ldu->base.connector) {
+               DRM_ERROR("connector doesn't match %p %p\n",
+                       set->connectors[0], &ldu->base.connector);
+               return -EINVAL;
+       }
+
+       /* ldu only supports one fb active at the time */
+       if (dev_priv->ldu_priv->fb && vfb &&
+           dev_priv->ldu_priv->fb != vfb) {
+               DRM_ERROR("Multiple framebuffers not supported\n");
+               return -EINVAL;
+       }
+
+       /* since they always map one to one these are safe */
+       connector = &ldu->base.connector;
+       encoder = &ldu->base.encoder;
+
+       /* should we turn the crtc off? */
+       if (set->num_connectors == 0 || !set->mode || !set->fb) {
+
+               connector->encoder = NULL;
+               encoder->crtc = NULL;
+               crtc->fb = NULL;
+
+               vmw_ldu_del_active(dev_priv, ldu);
+
+               vmw_ldu_commit_list(dev_priv);
+
+               return 0;
+       }
+
+
+       /* we now know we want to set a mode */
+       mode = set->mode;
+       fb = set->fb;
+
+       if (set->x + mode->hdisplay > fb->width ||
+           set->y + mode->vdisplay > fb->height) {
+               DRM_ERROR("set outside of framebuffer\n");
+               return -EINVAL;
+       }
+
+       vmw_fb_off(dev_priv);
+
+       crtc->fb = fb;
+       encoder->crtc = crtc;
+       connector->encoder = encoder;
+       crtc->x = set->x;
+       crtc->y = set->y;
+       crtc->mode = *mode;
+
+       vmw_ldu_add_active(dev_priv, ldu, vfb);
+
+       vmw_ldu_commit_list(dev_priv);
+
+       return 0;
+}
+
+static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
+       .save = vmw_ldu_crtc_save,
+       .restore = vmw_ldu_crtc_restore,
+       .cursor_set = vmw_du_crtc_cursor_set,
+       .cursor_move = vmw_du_crtc_cursor_move,
+       .gamma_set = vmw_ldu_crtc_gamma_set,
+       .destroy = vmw_ldu_crtc_destroy,
+       .set_config = vmw_ldu_crtc_set_config,
+};
+
+/*
+ * Legacy Display Unit encoder functions
+ */
+
+static void vmw_ldu_encoder_destroy(struct drm_encoder *encoder)
+{
+       vmw_ldu_destroy(vmw_encoder_to_ldu(encoder));
+}
+
+static struct drm_encoder_funcs vmw_legacy_encoder_funcs = {
+       .destroy = vmw_ldu_encoder_destroy,
+};
+
+/*
+ * Legacy Display Unit connector functions
+ */
+
+static void vmw_ldu_connector_dpms(struct drm_connector *connector, int mode)
+{
+}
+
+static void vmw_ldu_connector_save(struct drm_connector *connector)
+{
+}
+
+static void vmw_ldu_connector_restore(struct drm_connector *connector)
+{
+}
+
+static enum drm_connector_status
+       vmw_ldu_connector_detect(struct drm_connector *connector)
+{
+       /* XXX vmwctrl should control connection status */
+       if (vmw_connector_to_ldu(connector)->base.unit == 0)
+               return connector_status_connected;
+       return connector_status_disconnected;
+}
+
+static struct drm_display_mode vmw_ldu_connector_builtin[] = {
+       /* 640x480@60Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                  752, 800, 0, 480, 489, 492, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 800x600@60Hz */
+       { DRM_MODE("800x600",
+                  DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+                  40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628,
+                  0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0, 768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1152x864@75Hz */
+       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+                  1344, 1600, 0, 864, 865, 868, 900, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x768@60Hz */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
+                  1472, 1664, 0, 768, 771, 778, 798, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x800@60Hz */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
+                  1480, 1680, 0, 800, 803, 809, 831, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1280x960@60Hz */
+       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
+                  1488, 1800, 0, 960, 961, 964, 1000, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x1024@60Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1360x768@60Hz */
+       { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
+                  1536, 1792, 0, 768, 771, 777, 795, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x1050@60Hz */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
+                  1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x900@60Hz */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
+                  1672, 1904, 0, 900, 903, 909, 934, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@60Hz */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
+                  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1680x1050@60Hz */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
+                  1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1792x1344@60Hz */
+       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
+                  2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1853x1392@60Hz */
+       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
+                  2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1200@60Hz */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
+                  2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1440@60Hz */
+       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
+                  2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 2560x1600@60Hz */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
+                  3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* Terminate */
+       { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) },
+};
+
+static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
+                                       uint32_t max_width, uint32_t max_height)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode = NULL;
+       int i;
+
+       for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
+               if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
+                   vmw_ldu_connector_builtin[i].vdisplay > max_height)
+                       continue;
+
+               mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]);
+               if (!mode)
+                       return 0;
+               mode->vrefresh = drm_mode_vrefresh(mode);
+
+               drm_mode_probed_add(connector, mode);
+       }
+
+       drm_mode_connector_list_update(connector);
+
+       return 1;
+}
+
+static int vmw_ldu_connector_set_property(struct drm_connector *connector,
+                                         struct drm_property *property,
+                                         uint64_t val)
+{
+       return 0;
+}
+
+static void vmw_ldu_connector_destroy(struct drm_connector *connector)
+{
+       vmw_ldu_destroy(vmw_connector_to_ldu(connector));
+}
+
+static struct drm_connector_funcs vmw_legacy_connector_funcs = {
+       .dpms = vmw_ldu_connector_dpms,
+       .save = vmw_ldu_connector_save,
+       .restore = vmw_ldu_connector_restore,
+       .detect = vmw_ldu_connector_detect,
+       .fill_modes = vmw_ldu_connector_fill_modes,
+       .set_property = vmw_ldu_connector_set_property,
+       .destroy = vmw_ldu_connector_destroy,
+};
+
+static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
+{
+       struct vmw_legacy_display_unit *ldu;
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct drm_crtc *crtc;
+
+       ldu = kzalloc(sizeof(*ldu), GFP_KERNEL);
+       if (!ldu)
+               return -ENOMEM;
+
+       ldu->unit = unit;
+       crtc = &ldu->base.crtc;
+       encoder = &ldu->base.encoder;
+       connector = &ldu->base.connector;
+
+       drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
+                          DRM_MODE_CONNECTOR_LVDS);
+       /* Initial status */
+       if (unit == 0)
+               connector->status = connector_status_connected;
+       else
+               connector->status = connector_status_disconnected;
+
+       drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
+                        DRM_MODE_ENCODER_LVDS);
+       drm_mode_connector_attach_encoder(connector, encoder);
+       encoder->possible_crtcs = (1 << unit);
+       encoder->possible_clones = 0;
+
+       INIT_LIST_HEAD(&ldu->active);
+
+       drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
+
+       drm_connector_attach_property(connector,
+                                     dev->mode_config.dirty_info_property,
+                                     1);
+
+       return 0;
+}
+
+int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
+{
+       if (dev_priv->ldu_priv) {
+               DRM_INFO("ldu system already on\n");
+               return -EINVAL;
+       }
+
+       dev_priv->ldu_priv = kmalloc(GFP_KERNEL, sizeof(*dev_priv->ldu_priv));
+
+       if (!dev_priv->ldu_priv)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&dev_priv->ldu_priv->active);
+       dev_priv->ldu_priv->num_active = 0;
+       dev_priv->ldu_priv->fb = NULL;
+
+       drm_mode_create_dirty_info_property(dev_priv->dev);
+
+       vmw_ldu_init(dev_priv, 0);
+       vmw_ldu_init(dev_priv, 1);
+       vmw_ldu_init(dev_priv, 2);
+       vmw_ldu_init(dev_priv, 3);
+       vmw_ldu_init(dev_priv, 4);
+       vmw_ldu_init(dev_priv, 5);
+       vmw_ldu_init(dev_priv, 6);
+       vmw_ldu_init(dev_priv, 7);
+
+       return 0;
+}
+
+int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
+{
+       if (!dev_priv->ldu_priv)
+               return -ENOSYS;
+
+       BUG_ON(!list_empty(&dev_priv->ldu_priv->active));
+
+       kfree(dev_priv->ldu_priv);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
new file mode 100644 (file)
index 0000000..bb6e6a0
--- /dev/null
@@ -0,0 +1,634 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+#include "ttm/ttm_placement.h"
+
+#include "svga_overlay.h"
+#include "svga_escape.h"
+
+#define VMW_MAX_NUM_STREAMS 1
+
+struct vmw_stream {
+       struct vmw_dma_buffer *buf;
+       bool claimed;
+       bool paused;
+       struct drm_vmw_control_stream_arg saved;
+};
+
+/**
+ * Overlay control
+ */
+struct vmw_overlay {
+       /*
+        * Each stream is a single overlay. In Xv these are called ports.
+        */
+       struct mutex mutex;
+       struct vmw_stream stream[VMW_MAX_NUM_STREAMS];
+};
+
+static inline struct vmw_overlay *vmw_overlay(struct drm_device *dev)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       return dev_priv ? dev_priv->overlay_priv : NULL;
+}
+
+struct vmw_escape_header {
+       uint32_t cmd;
+       SVGAFifoCmdEscape body;
+};
+
+struct vmw_escape_video_flush {
+       struct vmw_escape_header escape;
+       SVGAEscapeVideoFlush flush;
+};
+
+static inline void fill_escape(struct vmw_escape_header *header,
+                              uint32_t size)
+{
+       header->cmd = SVGA_CMD_ESCAPE;
+       header->body.nsid = SVGA_ESCAPE_NSID_VMWARE;
+       header->body.size = size;
+}
+
+static inline void fill_flush(struct vmw_escape_video_flush *cmd,
+                             uint32_t stream_id)
+{
+       fill_escape(&cmd->escape, sizeof(cmd->flush));
+       cmd->flush.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH;
+       cmd->flush.streamId = stream_id;
+}
+
+/**
+ * Pin or unpin a buffer in vram.
+ *
+ * @dev_priv:  Driver private.
+ * @buf:  DMA buffer to pin or unpin.
+ * @pin:  Pin buffer in vram if true.
+ * @interruptible:  Use interruptible wait.
+ *
+ * Takes the current masters ttm lock in read.
+ *
+ * Returns
+ * -ERESTARTSYS if interrupted by a signal.
+ */
+static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv,
+                                 struct vmw_dma_buffer *buf,
+                                 bool pin, bool interruptible)
+{
+       struct ttm_buffer_object *bo = &buf->base;
+       struct ttm_bo_global *glob = bo->glob;
+       struct ttm_placement *overlay_placement = &vmw_vram_placement;
+       int ret;
+
+       ret = ttm_read_lock(&dev_priv->active_master->lock, interruptible);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
+       if (unlikely(ret != 0))
+               goto err;
+
+       if (buf->gmr_bound) {
+               vmw_gmr_unbind(dev_priv, buf->gmr_id);
+               spin_lock(&glob->lru_lock);
+               ida_remove(&dev_priv->gmr_ida, buf->gmr_id);
+               spin_unlock(&glob->lru_lock);
+               buf->gmr_bound = NULL;
+       }
+
+       if (pin)
+               overlay_placement = &vmw_vram_ne_placement;
+
+       ret = ttm_bo_validate(bo, overlay_placement, interruptible, false);
+
+       ttm_bo_unreserve(bo);
+
+err:
+       ttm_read_unlock(&dev_priv->active_master->lock);
+
+       return ret;
+}
+
+/**
+ * Send put command to hw.
+ *
+ * Returns
+ * -ERESTARTSYS if interrupted by a signal.
+ */
+static int vmw_overlay_send_put(struct vmw_private *dev_priv,
+                               struct vmw_dma_buffer *buf,
+                               struct drm_vmw_control_stream_arg *arg,
+                               bool interruptible)
+{
+       struct {
+               struct vmw_escape_header escape;
+               struct {
+                       struct {
+                               uint32_t cmdType;
+                               uint32_t streamId;
+                       } header;
+                       struct {
+                               uint32_t registerId;
+                               uint32_t value;
+                       } items[SVGA_VIDEO_PITCH_3 + 1];
+               } body;
+               struct vmw_escape_video_flush flush;
+       } *cmds;
+       uint32_t offset;
+       int i, ret;
+
+       for (;;) {
+               cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds));
+               if (cmds)
+                       break;
+
+               ret = vmw_fallback_wait(dev_priv, false, true, 0,
+                                       interruptible, 3*HZ);
+               if (interruptible && ret == -ERESTARTSYS)
+                       return ret;
+               else
+                       BUG_ON(ret != 0);
+       }
+
+       fill_escape(&cmds->escape, sizeof(cmds->body));
+       cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
+       cmds->body.header.streamId = arg->stream_id;
+
+       for (i = 0; i <= SVGA_VIDEO_PITCH_3; i++)
+               cmds->body.items[i].registerId = i;
+
+       offset = buf->base.offset + arg->offset;
+
+       cmds->body.items[SVGA_VIDEO_ENABLED].value     = true;
+       cmds->body.items[SVGA_VIDEO_FLAGS].value       = arg->flags;
+       cmds->body.items[SVGA_VIDEO_DATA_OFFSET].value = offset;
+       cmds->body.items[SVGA_VIDEO_FORMAT].value      = arg->format;
+       cmds->body.items[SVGA_VIDEO_COLORKEY].value    = arg->color_key;
+       cmds->body.items[SVGA_VIDEO_SIZE].value        = arg->size;
+       cmds->body.items[SVGA_VIDEO_WIDTH].value       = arg->width;
+       cmds->body.items[SVGA_VIDEO_HEIGHT].value      = arg->height;
+       cmds->body.items[SVGA_VIDEO_SRC_X].value       = arg->src.x;
+       cmds->body.items[SVGA_VIDEO_SRC_Y].value       = arg->src.y;
+       cmds->body.items[SVGA_VIDEO_SRC_WIDTH].value   = arg->src.w;
+       cmds->body.items[SVGA_VIDEO_SRC_HEIGHT].value  = arg->src.h;
+       cmds->body.items[SVGA_VIDEO_DST_X].value       = arg->dst.x;
+       cmds->body.items[SVGA_VIDEO_DST_Y].value       = arg->dst.y;
+       cmds->body.items[SVGA_VIDEO_DST_WIDTH].value   = arg->dst.w;
+       cmds->body.items[SVGA_VIDEO_DST_HEIGHT].value  = arg->dst.h;
+       cmds->body.items[SVGA_VIDEO_PITCH_1].value     = arg->pitch[0];
+       cmds->body.items[SVGA_VIDEO_PITCH_2].value     = arg->pitch[1];
+       cmds->body.items[SVGA_VIDEO_PITCH_3].value     = arg->pitch[2];
+
+       fill_flush(&cmds->flush, arg->stream_id);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmds));
+
+       return 0;
+}
+
+/**
+ * Send stop command to hw.
+ *
+ * Returns
+ * -ERESTARTSYS if interrupted by a signal.
+ */
+static int vmw_overlay_send_stop(struct vmw_private *dev_priv,
+                                uint32_t stream_id,
+                                bool interruptible)
+{
+       struct {
+               struct vmw_escape_header escape;
+               SVGAEscapeVideoSetRegs body;
+               struct vmw_escape_video_flush flush;
+       } *cmds;
+       int ret;
+
+       for (;;) {
+               cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds));
+               if (cmds)
+                       break;
+
+               ret = vmw_fallback_wait(dev_priv, false, true, 0,
+                                       interruptible, 3*HZ);
+               if (interruptible && ret == -ERESTARTSYS)
+                       return ret;
+               else
+                       BUG_ON(ret != 0);
+       }
+
+       fill_escape(&cmds->escape, sizeof(cmds->body));
+       cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
+       cmds->body.header.streamId = stream_id;
+       cmds->body.items[0].registerId = SVGA_VIDEO_ENABLED;
+       cmds->body.items[0].value = false;
+       fill_flush(&cmds->flush, stream_id);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmds));
+
+       return 0;
+}
+
+/**
+ * Stop or pause a stream.
+ *
+ * If the stream is paused the no evict flag is removed from the buffer
+ * but left in vram. This allows for instance mode_set to evict it
+ * should it need to.
+ *
+ * The caller must hold the overlay lock.
+ *
+ * @stream_id which stream to stop/pause.
+ * @pause true to pause, false to stop completely.
+ */
+static int vmw_overlay_stop(struct vmw_private *dev_priv,
+                           uint32_t stream_id, bool pause,
+                           bool interruptible)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       struct vmw_stream *stream = &overlay->stream[stream_id];
+       int ret;
+
+       /* no buffer attached the stream is completely stopped */
+       if (!stream->buf)
+               return 0;
+
+       /* If the stream is paused this is already done */
+       if (!stream->paused) {
+               ret = vmw_overlay_send_stop(dev_priv, stream_id,
+                                           interruptible);
+               if (ret)
+                       return ret;
+
+               /* We just remove the NO_EVICT flag so no -ENOMEM */
+               ret = vmw_dmabuf_pin_in_vram(dev_priv, stream->buf, false,
+                                            interruptible);
+               if (interruptible && ret == -ERESTARTSYS)
+                       return ret;
+               else
+                       BUG_ON(ret != 0);
+       }
+
+       if (!pause) {
+               vmw_dmabuf_unreference(&stream->buf);
+               stream->paused = false;
+       } else {
+               stream->paused = true;
+       }
+
+       return 0;
+}
+
+/**
+ * Update a stream and send any put or stop fifo commands needed.
+ *
+ * The caller must hold the overlay lock.
+ *
+ * Returns
+ * -ENOMEM if buffer doesn't fit in vram.
+ * -ERESTARTSYS if interrupted.
+ */
+static int vmw_overlay_update_stream(struct vmw_private *dev_priv,
+                                    struct vmw_dma_buffer *buf,
+                                    struct drm_vmw_control_stream_arg *arg,
+                                    bool interruptible)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       struct vmw_stream *stream = &overlay->stream[arg->stream_id];
+       int ret = 0;
+
+       if (!buf)
+               return -EINVAL;
+
+       DRM_DEBUG("   %s: old %p, new %p, %spaused\n", __func__,
+                 stream->buf, buf, stream->paused ? "" : "not ");
+
+       if (stream->buf != buf) {
+               ret = vmw_overlay_stop(dev_priv, arg->stream_id,
+                                      false, interruptible);
+               if (ret)
+                       return ret;
+       } else if (!stream->paused) {
+               /* If the buffers match and not paused then just send
+                * the put command, no need to do anything else.
+                */
+               ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible);
+               if (ret == 0)
+                       stream->saved = *arg;
+               else
+                       BUG_ON(!interruptible);
+
+               return ret;
+       }
+
+       /* We don't start the old stream if we are interrupted.
+        * Might return -ENOMEM if it can't fit the buffer in vram.
+        */
+       ret = vmw_dmabuf_pin_in_vram(dev_priv, buf, true, interruptible);
+       if (ret)
+               return ret;
+
+       ret = vmw_overlay_send_put(dev_priv, buf, arg, interruptible);
+       if (ret) {
+               /* This one needs to happen no matter what. We only remove
+                * the NO_EVICT flag so this is safe from -ENOMEM.
+                */
+               BUG_ON(vmw_dmabuf_pin_in_vram(dev_priv, buf, false, false) != 0);
+               return ret;
+       }
+
+       if (stream->buf != buf)
+               stream->buf = vmw_dmabuf_reference(buf);
+       stream->saved = *arg;
+
+       return 0;
+}
+
+/**
+ * Stop all streams.
+ *
+ * Used by the fb code when starting.
+ *
+ * Takes the overlay lock.
+ */
+int vmw_overlay_stop_all(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       int i, ret;
+
+       if (!overlay)
+               return 0;
+
+       mutex_lock(&overlay->mutex);
+
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+               struct vmw_stream *stream = &overlay->stream[i];
+               if (!stream->buf)
+                       continue;
+
+               ret = vmw_overlay_stop(dev_priv, i, false, false);
+               WARN_ON(ret != 0);
+       }
+
+       mutex_unlock(&overlay->mutex);
+
+       return 0;
+}
+
+/**
+ * Try to resume all paused streams.
+ *
+ * Used by the kms code after moving a new scanout buffer to vram.
+ *
+ * Takes the overlay lock.
+ */
+int vmw_overlay_resume_all(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       int i, ret;
+
+       if (!overlay)
+               return 0;
+
+       mutex_lock(&overlay->mutex);
+
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+               struct vmw_stream *stream = &overlay->stream[i];
+               if (!stream->paused)
+                       continue;
+
+               ret = vmw_overlay_update_stream(dev_priv, stream->buf,
+                                               &stream->saved, false);
+               if (ret != 0)
+                       DRM_INFO("%s: *warning* failed to resume stream %i\n",
+                                __func__, i);
+       }
+
+       mutex_unlock(&overlay->mutex);
+
+       return 0;
+}
+
+/**
+ * Pauses all active streams.
+ *
+ * Used by the kms code when moving a new scanout buffer to vram.
+ *
+ * Takes the overlay lock.
+ */
+int vmw_overlay_pause_all(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       int i, ret;
+
+       if (!overlay)
+               return 0;
+
+       mutex_lock(&overlay->mutex);
+
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+               if (overlay->stream[i].paused)
+                       DRM_INFO("%s: *warning* stream %i already paused\n",
+                                __func__, i);
+               ret = vmw_overlay_stop(dev_priv, i, true, false);
+               WARN_ON(ret != 0);
+       }
+
+       mutex_unlock(&overlay->mutex);
+
+       return 0;
+}
+
+int vmw_overlay_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       struct drm_vmw_control_stream_arg *arg =
+           (struct drm_vmw_control_stream_arg *)data;
+       struct vmw_dma_buffer *buf;
+       struct vmw_resource *res;
+       int ret;
+
+       if (!overlay)
+               return -ENOSYS;
+
+       ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res);
+       if (ret)
+               return ret;
+
+       mutex_lock(&overlay->mutex);
+
+       if (!arg->enabled) {
+               ret = vmw_overlay_stop(dev_priv, arg->stream_id, false, true);
+               goto out_unlock;
+       }
+
+       ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf);
+       if (ret)
+               goto out_unlock;
+
+       ret = vmw_overlay_update_stream(dev_priv, buf, arg, true);
+
+       vmw_dmabuf_unreference(&buf);
+
+out_unlock:
+       mutex_unlock(&overlay->mutex);
+       vmw_resource_unreference(&res);
+
+       return ret;
+}
+
+int vmw_overlay_num_overlays(struct vmw_private *dev_priv)
+{
+       if (!dev_priv->overlay_priv)
+               return 0;
+
+       return VMW_MAX_NUM_STREAMS;
+}
+
+int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       int i, k;
+
+       if (!overlay)
+               return 0;
+
+       mutex_lock(&overlay->mutex);
+
+       for (i = 0, k = 0; i < VMW_MAX_NUM_STREAMS; i++)
+               if (!overlay->stream[i].claimed)
+                       k++;
+
+       mutex_unlock(&overlay->mutex);
+
+       return k;
+}
+
+int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       int i;
+
+       if (!overlay)
+               return -ENOSYS;
+
+       mutex_lock(&overlay->mutex);
+
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+
+               if (overlay->stream[i].claimed)
+                       continue;
+
+               overlay->stream[i].claimed = true;
+               *out = i;
+               mutex_unlock(&overlay->mutex);
+               return 0;
+       }
+
+       mutex_unlock(&overlay->mutex);
+       return -ESRCH;
+}
+
+int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+
+       BUG_ON(stream_id >= VMW_MAX_NUM_STREAMS);
+
+       if (!overlay)
+               return -ENOSYS;
+
+       mutex_lock(&overlay->mutex);
+
+       WARN_ON(!overlay->stream[stream_id].claimed);
+       vmw_overlay_stop(dev_priv, stream_id, false, false);
+       overlay->stream[stream_id].claimed = false;
+
+       mutex_unlock(&overlay->mutex);
+       return 0;
+}
+
+int vmw_overlay_init(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay;
+       int i;
+
+       if (dev_priv->overlay_priv)
+               return -EINVAL;
+
+       if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_VIDEO) &&
+            (dev_priv->fifo.capabilities & SVGA_FIFO_CAP_ESCAPE)) {
+               DRM_INFO("hardware doesn't support overlays\n");
+               return -ENOSYS;
+       }
+
+       overlay = kmalloc(GFP_KERNEL, sizeof(*overlay));
+       if (!overlay)
+               return -ENOMEM;
+
+       memset(overlay, 0, sizeof(*overlay));
+       mutex_init(&overlay->mutex);
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+               overlay->stream[i].buf = NULL;
+               overlay->stream[i].paused = false;
+               overlay->stream[i].claimed = false;
+       }
+
+       dev_priv->overlay_priv = overlay;
+
+       return 0;
+}
+
+int vmw_overlay_close(struct vmw_private *dev_priv)
+{
+       struct vmw_overlay *overlay = dev_priv->overlay_priv;
+       bool forgotten_buffer = false;
+       int i;
+
+       if (!overlay)
+               return -ENOSYS;
+
+       for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+               if (overlay->stream[i].buf) {
+                       forgotten_buffer = true;
+                       vmw_overlay_stop(dev_priv, i, false, false);
+               }
+       }
+
+       WARN_ON(forgotten_buffer);
+
+       dev_priv->overlay_priv = NULL;
+       kfree(overlay);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h
new file mode 100644 (file)
index 0000000..9d0dd3a
--- /dev/null
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * This file contains virtual hardware defines for kernel space.
+ */
+
+#ifndef _VMWGFX_REG_H_
+#define _VMWGFX_REG_H_
+
+#include <linux/types.h>
+
+#define VMWGFX_INDEX_PORT     0x0
+#define VMWGFX_VALUE_PORT     0x1
+#define VMWGFX_IRQSTATUS_PORT 0x8
+
+struct svga_guest_mem_descriptor {
+       __le32 ppn;
+       __le32 num_pages;
+};
+
+struct svga_fifo_cmd_fence {
+       __le32 fence;
+};
+
+#define SVGA_SYNC_GENERIC         1
+#define SVGA_SYNC_FIFOFULL        2
+
+#include "svga_types.h"
+
+#include "svga3d_reg.h"
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
new file mode 100644 (file)
index 0000000..a1ceed0
--- /dev/null
@@ -0,0 +1,1192 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "vmwgfx_drm.h"
+#include "ttm/ttm_object.h"
+#include "ttm/ttm_placement.h"
+#include "drmP.h"
+
+#define VMW_RES_CONTEXT ttm_driver_type0
+#define VMW_RES_SURFACE ttm_driver_type1
+#define VMW_RES_STREAM ttm_driver_type2
+
+struct vmw_user_context {
+       struct ttm_base_object base;
+       struct vmw_resource res;
+};
+
+struct vmw_user_surface {
+       struct ttm_base_object base;
+       struct vmw_surface srf;
+};
+
+struct vmw_user_dma_buffer {
+       struct ttm_base_object base;
+       struct vmw_dma_buffer dma;
+};
+
+struct vmw_bo_user_rep {
+       uint32_t handle;
+       uint64_t map_handle;
+};
+
+struct vmw_stream {
+       struct vmw_resource res;
+       uint32_t stream_id;
+};
+
+struct vmw_user_stream {
+       struct ttm_base_object base;
+       struct vmw_stream stream;
+};
+
+static inline struct vmw_dma_buffer *
+vmw_dma_buffer(struct ttm_buffer_object *bo)
+{
+       return container_of(bo, struct vmw_dma_buffer, base);
+}
+
+static inline struct vmw_user_dma_buffer *
+vmw_user_dma_buffer(struct ttm_buffer_object *bo)
+{
+       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+       return container_of(vmw_bo, struct vmw_user_dma_buffer, dma);
+}
+
+struct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
+{
+       kref_get(&res->kref);
+       return res;
+}
+
+static void vmw_resource_release(struct kref *kref)
+{
+       struct vmw_resource *res =
+           container_of(kref, struct vmw_resource, kref);
+       struct vmw_private *dev_priv = res->dev_priv;
+
+       idr_remove(res->idr, res->id);
+       write_unlock(&dev_priv->resource_lock);
+
+       if (likely(res->hw_destroy != NULL))
+               res->hw_destroy(res);
+
+       if (res->res_free != NULL)
+               res->res_free(res);
+       else
+               kfree(res);
+
+       write_lock(&dev_priv->resource_lock);
+}
+
+void vmw_resource_unreference(struct vmw_resource **p_res)
+{
+       struct vmw_resource *res = *p_res;
+       struct vmw_private *dev_priv = res->dev_priv;
+
+       *p_res = NULL;
+       write_lock(&dev_priv->resource_lock);
+       kref_put(&res->kref, vmw_resource_release);
+       write_unlock(&dev_priv->resource_lock);
+}
+
+static int vmw_resource_init(struct vmw_private *dev_priv,
+                            struct vmw_resource *res,
+                            struct idr *idr,
+                            enum ttm_object_type obj_type,
+                            void (*res_free) (struct vmw_resource *res))
+{
+       int ret;
+
+       kref_init(&res->kref);
+       res->hw_destroy = NULL;
+       res->res_free = res_free;
+       res->res_type = obj_type;
+       res->idr = idr;
+       res->avail = false;
+       res->dev_priv = dev_priv;
+
+       do {
+               if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+                       return -ENOMEM;
+
+               write_lock(&dev_priv->resource_lock);
+               ret = idr_get_new_above(idr, res, 1, &res->id);
+               write_unlock(&dev_priv->resource_lock);
+
+       } while (ret == -EAGAIN);
+
+       return ret;
+}
+
+/**
+ * vmw_resource_activate
+ *
+ * @res:        Pointer to the newly created resource
+ * @hw_destroy: Destroy function. NULL if none.
+ *
+ * Activate a resource after the hardware has been made aware of it.
+ * Set tye destroy function to @destroy. Typically this frees the
+ * resource and destroys the hardware resources associated with it.
+ * Activate basically means that the function vmw_resource_lookup will
+ * find it.
+ */
+
+static void vmw_resource_activate(struct vmw_resource *res,
+                                 void (*hw_destroy) (struct vmw_resource *))
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+
+       write_lock(&dev_priv->resource_lock);
+       res->avail = true;
+       res->hw_destroy = hw_destroy;
+       write_unlock(&dev_priv->resource_lock);
+}
+
+struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv,
+                                        struct idr *idr, int id)
+{
+       struct vmw_resource *res;
+
+       read_lock(&dev_priv->resource_lock);
+       res = idr_find(idr, id);
+       if (res && res->avail)
+               kref_get(&res->kref);
+       else
+               res = NULL;
+       read_unlock(&dev_priv->resource_lock);
+
+       if (unlikely(res == NULL))
+               return NULL;
+
+       return res;
+}
+
+/**
+ * Context management:
+ */
+
+static void vmw_hw_context_destroy(struct vmw_resource *res)
+{
+
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroyContext body;
+       } *cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "destruction.\n");
+               return;
+       }
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
+       cmd->header.size = cpu_to_le32(sizeof(cmd->body));
+       cmd->body.cid = cpu_to_le32(res->id);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+}
+
+static int vmw_context_init(struct vmw_private *dev_priv,
+                           struct vmw_resource *res,
+                           void (*res_free) (struct vmw_resource *res))
+{
+       int ret;
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineContext body;
+       } *cmd;
+
+       ret = vmw_resource_init(dev_priv, res, &dev_priv->context_idr,
+                               VMW_RES_CONTEXT, res_free);
+
+       if (unlikely(ret != 0)) {
+               if (res_free == NULL)
+                       kfree(res);
+               else
+                       res_free(res);
+               return ret;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               vmw_resource_unreference(&res);
+               return -ENOMEM;
+       }
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
+       cmd->header.size = cpu_to_le32(sizeof(cmd->body));
+       cmd->body.cid = cpu_to_le32(res->id);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       vmw_resource_activate(res, vmw_hw_context_destroy);
+       return 0;
+}
+
+struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
+{
+       struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+       int ret;
+
+       if (unlikely(res == NULL))
+               return NULL;
+
+       ret = vmw_context_init(dev_priv, res, NULL);
+       return (ret == 0) ? res : NULL;
+}
+
+/**
+ * User-space context management:
+ */
+
+static void vmw_user_context_free(struct vmw_resource *res)
+{
+       struct vmw_user_context *ctx =
+           container_of(res, struct vmw_user_context, res);
+
+       kfree(ctx);
+}
+
+/**
+ * This function is called when user space has no more references on the
+ * base object. It releases the base-object's reference on the resource object.
+ */
+
+static void vmw_user_context_base_release(struct ttm_base_object **p_base)
+{
+       struct ttm_base_object *base = *p_base;
+       struct vmw_user_context *ctx =
+           container_of(base, struct vmw_user_context, base);
+       struct vmw_resource *res = &ctx->res;
+
+       *p_base = NULL;
+       vmw_resource_unreference(&res);
+}
+
+int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_resource *res;
+       struct vmw_user_context *ctx;
+       struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret = 0;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->context_idr, arg->cid);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_context_free) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ctx = container_of(res, struct vmw_user_context, res);
+       if (ctx->base.tfile != tfile && !ctx->base.shareable) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       ttm_ref_object_base_unref(tfile, ctx->base.hash.key, TTM_REF_USAGE);
+out:
+       vmw_resource_unreference(&res);
+       return ret;
+}
+
+int vmw_context_define_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_user_context *ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       struct vmw_resource *res;
+       struct vmw_resource *tmp;
+       struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret;
+
+       if (unlikely(ctx == NULL))
+               return -ENOMEM;
+
+       res = &ctx->res;
+       ctx->base.shareable = false;
+       ctx->base.tfile = NULL;
+
+       ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
+       if (unlikely(ret != 0))
+               return ret;
+
+       tmp = vmw_resource_reference(&ctx->res);
+       ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
+                                  &vmw_user_context_base_release, NULL);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&tmp);
+               goto out_err;
+       }
+
+       arg->cid = res->id;
+out_err:
+       vmw_resource_unreference(&res);
+       return ret;
+
+}
+
+int vmw_context_check(struct vmw_private *dev_priv,
+                     struct ttm_object_file *tfile,
+                     int id)
+{
+       struct vmw_resource *res;
+       int ret = 0;
+
+       read_lock(&dev_priv->resource_lock);
+       res = idr_find(&dev_priv->context_idr, id);
+       if (res && res->avail) {
+               struct vmw_user_context *ctx =
+                       container_of(res, struct vmw_user_context, res);
+               if (ctx->base.tfile != tfile && !ctx->base.shareable)
+                       ret = -EPERM;
+       } else
+               ret = -EINVAL;
+       read_unlock(&dev_priv->resource_lock);
+
+       return ret;
+}
+
+
+/**
+ * Surface management.
+ */
+
+static void vmw_hw_surface_destroy(struct vmw_resource *res)
+{
+
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroySurface body;
+       } *cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "destruction.\n");
+               return;
+       }
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_SURFACE_DESTROY);
+       cmd->header.size = cpu_to_le32(sizeof(cmd->body));
+       cmd->body.sid = cpu_to_le32(res->id);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+}
+
+void vmw_surface_res_free(struct vmw_resource *res)
+{
+       struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
+
+       kfree(srf->sizes);
+       kfree(srf->snooper.image);
+       kfree(srf);
+}
+
+int vmw_surface_init(struct vmw_private *dev_priv,
+                    struct vmw_surface *srf,
+                    void (*res_free) (struct vmw_resource *res))
+{
+       int ret;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineSurface body;
+       } *cmd;
+       SVGA3dSize *cmd_size;
+       struct vmw_resource *res = &srf->res;
+       struct drm_vmw_size *src_size;
+       size_t submit_size;
+       uint32_t cmd_len;
+       int i;
+
+       BUG_ON(res_free == NULL);
+       ret = vmw_resource_init(dev_priv, res, &dev_priv->surface_idr,
+                               VMW_RES_SURFACE, res_free);
+
+       if (unlikely(ret != 0)) {
+               res_free(res);
+               return ret;
+       }
+
+       submit_size = sizeof(*cmd) + srf->num_sizes * sizeof(SVGA3dSize);
+       cmd_len = sizeof(cmd->body) + srf->num_sizes * sizeof(SVGA3dSize);
+
+       cmd = vmw_fifo_reserve(dev_priv, submit_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed for create surface.\n");
+               vmw_resource_unreference(&res);
+               return -ENOMEM;
+       }
+
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_SURFACE_DEFINE);
+       cmd->header.size = cpu_to_le32(cmd_len);
+       cmd->body.sid = cpu_to_le32(res->id);
+       cmd->body.surfaceFlags = cpu_to_le32(srf->flags);
+       cmd->body.format = cpu_to_le32(srf->format);
+       for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
+               cmd->body.face[i].numMipLevels =
+                   cpu_to_le32(srf->mip_levels[i]);
+       }
+
+       cmd += 1;
+       cmd_size = (SVGA3dSize *) cmd;
+       src_size = srf->sizes;
+
+       for (i = 0; i < srf->num_sizes; ++i, cmd_size++, src_size++) {
+               cmd_size->width = cpu_to_le32(src_size->width);
+               cmd_size->height = cpu_to_le32(src_size->height);
+               cmd_size->depth = cpu_to_le32(src_size->depth);
+       }
+
+       vmw_fifo_commit(dev_priv, submit_size);
+       vmw_resource_activate(res, vmw_hw_surface_destroy);
+       return 0;
+}
+
+static void vmw_user_surface_free(struct vmw_resource *res)
+{
+       struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
+       struct vmw_user_surface *user_srf =
+           container_of(srf, struct vmw_user_surface, srf);
+
+       kfree(srf->sizes);
+       kfree(srf->snooper.image);
+       kfree(user_srf);
+}
+
+int vmw_user_surface_lookup(struct vmw_private *dev_priv,
+                           struct ttm_object_file *tfile,
+                           int sid, struct vmw_surface **out)
+{
+       struct vmw_resource *res;
+       struct vmw_surface *srf;
+       struct vmw_user_surface *user_srf;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, sid);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_surface_free)
+               return -EINVAL;
+
+       srf = container_of(res, struct vmw_surface, res);
+       user_srf = container_of(srf, struct vmw_user_surface, srf);
+       if (user_srf->base.tfile != tfile && !user_srf->base.shareable)
+               return -EPERM;
+
+       *out = srf;
+       return 0;
+}
+
+static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
+{
+       struct ttm_base_object *base = *p_base;
+       struct vmw_user_surface *user_srf =
+           container_of(base, struct vmw_user_surface, base);
+       struct vmw_resource *res = &user_srf->srf.res;
+
+       *p_base = NULL;
+       vmw_resource_unreference(&res);
+}
+
+int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_resource *res;
+       struct vmw_surface *srf;
+       struct vmw_user_surface *user_srf;
+       struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret = 0;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, arg->sid);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_surface_free) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       srf = container_of(res, struct vmw_surface, res);
+       user_srf = container_of(srf, struct vmw_user_surface, srf);
+       if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       ttm_ref_object_base_unref(tfile, user_srf->base.hash.key,
+                                 TTM_REF_USAGE);
+out:
+       vmw_resource_unreference(&res);
+       return ret;
+}
+
+int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_user_surface *user_srf =
+           kmalloc(sizeof(*user_srf), GFP_KERNEL);
+       struct vmw_surface *srf;
+       struct vmw_resource *res;
+       struct vmw_resource *tmp;
+       union drm_vmw_surface_create_arg *arg =
+           (union drm_vmw_surface_create_arg *)data;
+       struct drm_vmw_surface_create_req *req = &arg->req;
+       struct drm_vmw_surface_arg *rep = &arg->rep;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct drm_vmw_size __user *user_sizes;
+       int ret;
+       int i;
+
+       if (unlikely(user_srf == NULL))
+               return -ENOMEM;
+
+       srf = &user_srf->srf;
+       res = &srf->res;
+
+       srf->flags = req->flags;
+       srf->format = req->format;
+       memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
+       srf->num_sizes = 0;
+       for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
+               srf->num_sizes += srf->mip_levels[i];
+
+       if (srf->num_sizes > DRM_VMW_MAX_SURFACE_FACES *
+           DRM_VMW_MAX_MIP_LEVELS) {
+               ret = -EINVAL;
+               goto out_err0;
+       }
+
+       srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
+       if (unlikely(srf->sizes == NULL)) {
+               ret = -ENOMEM;
+               goto out_err0;
+       }
+
+       user_sizes = (struct drm_vmw_size __user *)(unsigned long)
+           req->size_addr;
+
+       ret = copy_from_user(srf->sizes, user_sizes,
+                            srf->num_sizes * sizeof(*srf->sizes));
+       if (unlikely(ret != 0))
+               goto out_err1;
+
+       user_srf->base.shareable = false;
+       user_srf->base.tfile = NULL;
+
+       /**
+        * From this point, the generic resource management functions
+        * destroy the object on failure.
+        */
+
+       ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
+       if (unlikely(ret != 0))
+               return ret;
+
+       tmp = vmw_resource_reference(&srf->res);
+       ret = ttm_base_object_init(tfile, &user_srf->base,
+                                  req->shareable, VMW_RES_SURFACE,
+                                  &vmw_user_surface_base_release, NULL);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&tmp);
+               vmw_resource_unreference(&res);
+               return ret;
+       }
+
+       if (srf->flags & (1 << 9) &&
+           srf->num_sizes == 1 &&
+           srf->sizes[0].width == 64 &&
+           srf->sizes[0].height == 64 &&
+           srf->format == SVGA3D_A8R8G8B8) {
+
+               srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
+               /* clear the image */
+               if (srf->snooper.image)
+                       memset(srf->snooper.image, 0x00, 64 * 64 * 4);
+               else
+                       DRM_ERROR("Failed to allocate cursor_image\n");
+
+       } else {
+               srf->snooper.image = NULL;
+       }
+       srf->snooper.crtc = NULL;
+
+       rep->sid = res->id;
+       vmw_resource_unreference(&res);
+       return 0;
+out_err1:
+       kfree(srf->sizes);
+out_err0:
+       kfree(user_srf);
+       return ret;
+}
+
+int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       union drm_vmw_surface_reference_arg *arg =
+           (union drm_vmw_surface_reference_arg *)data;
+       struct drm_vmw_surface_arg *req = &arg->req;
+       struct drm_vmw_surface_create_req *rep = &arg->rep;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_resource *res;
+       struct vmw_surface *srf;
+       struct vmw_user_surface *user_srf;
+       struct drm_vmw_size __user *user_sizes;
+       int ret;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, req->sid);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_surface_free) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       srf = container_of(res, struct vmw_surface, res);
+       user_srf = container_of(srf, struct vmw_user_surface, srf);
+       if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
+               DRM_ERROR("Tried to reference none shareable surface\n");
+               ret = -EPERM;
+               goto out;
+       }
+
+       ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not add a reference to a surface.\n");
+               goto out;
+       }
+
+       rep->flags = srf->flags;
+       rep->format = srf->format;
+       memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
+       user_sizes = (struct drm_vmw_size __user *)(unsigned long)
+           rep->size_addr;
+
+       if (user_sizes)
+               ret = copy_to_user(user_sizes, srf->sizes,
+                                  srf->num_sizes * sizeof(*srf->sizes));
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("copy_to_user failed %p %u\n",
+                         user_sizes, srf->num_sizes);
+               /**
+                * FIXME: Unreference surface here?
+                */
+               goto out;
+       }
+out:
+       vmw_resource_unreference(&res);
+       return ret;
+}
+
+int vmw_surface_check(struct vmw_private *dev_priv,
+                     struct ttm_object_file *tfile,
+                     int id)
+{
+       struct vmw_resource *res;
+       int ret = 0;
+
+       read_lock(&dev_priv->resource_lock);
+       res = idr_find(&dev_priv->surface_idr, id);
+       if (res && res->avail) {
+               struct vmw_surface *srf =
+                       container_of(res, struct vmw_surface, res);
+               struct vmw_user_surface *usrf =
+                       container_of(srf, struct vmw_user_surface, srf);
+
+               if (usrf->base.tfile != tfile && !usrf->base.shareable)
+                       ret = -EPERM;
+       } else
+               ret = -EINVAL;
+       read_unlock(&dev_priv->resource_lock);
+
+       return ret;
+}
+
+/**
+ * Buffer management.
+ */
+
+static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob,
+                                 unsigned long num_pages)
+{
+       static size_t bo_user_size = ~0;
+
+       size_t page_array_size =
+           (num_pages * sizeof(void *) + PAGE_SIZE - 1) & PAGE_MASK;
+
+       if (unlikely(bo_user_size == ~0)) {
+               bo_user_size = glob->ttm_bo_extra_size +
+                   ttm_round_pot(sizeof(struct vmw_dma_buffer));
+       }
+
+       return bo_user_size + page_array_size;
+}
+
+void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
+{
+       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+       struct ttm_bo_global *glob = bo->glob;
+       struct vmw_private *dev_priv =
+               container_of(bo->bdev, struct vmw_private, bdev);
+
+       ttm_mem_global_free(glob->mem_glob, bo->acc_size);
+       if (vmw_bo->gmr_bound) {
+               vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
+               spin_lock(&glob->lru_lock);
+               ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
+               spin_unlock(&glob->lru_lock);
+       }
+       kfree(vmw_bo);
+}
+
+int vmw_dmabuf_init(struct vmw_private *dev_priv,
+                   struct vmw_dma_buffer *vmw_bo,
+                   size_t size, struct ttm_placement *placement,
+                   bool interruptible,
+                   void (*bo_free) (struct ttm_buffer_object *bo))
+{
+       struct ttm_bo_device *bdev = &dev_priv->bdev;
+       struct ttm_mem_global *mem_glob = bdev->glob->mem_glob;
+       size_t acc_size;
+       int ret;
+
+       BUG_ON(!bo_free);
+
+       acc_size =
+           vmw_dmabuf_acc_size(bdev->glob,
+                               (size + PAGE_SIZE - 1) >> PAGE_SHIFT);
+
+       ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false);
+       if (unlikely(ret != 0)) {
+               /* we must free the bo here as
+                * ttm_buffer_object_init does so as well */
+               bo_free(&vmw_bo->base);
+               return ret;
+       }
+
+       memset(vmw_bo, 0, sizeof(*vmw_bo));
+
+       INIT_LIST_HEAD(&vmw_bo->gmr_lru);
+       INIT_LIST_HEAD(&vmw_bo->validate_list);
+       vmw_bo->gmr_id = 0;
+       vmw_bo->gmr_bound = false;
+
+       ret = ttm_bo_init(bdev, &vmw_bo->base, size,
+                         ttm_bo_type_device, placement,
+                         0, 0, interruptible,
+                         NULL, acc_size, bo_free);
+       return ret;
+}
+
+static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
+{
+       struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
+       struct vmw_dma_buffer *vmw_bo = &vmw_user_bo->dma;
+       struct ttm_bo_global *glob = bo->glob;
+       struct vmw_private *dev_priv =
+               container_of(bo->bdev, struct vmw_private, bdev);
+
+       ttm_mem_global_free(glob->mem_glob, bo->acc_size);
+       if (vmw_bo->gmr_bound) {
+               vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
+               spin_lock(&glob->lru_lock);
+               ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
+               spin_unlock(&glob->lru_lock);
+       }
+       kfree(vmw_user_bo);
+}
+
+static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
+{
+       struct vmw_user_dma_buffer *vmw_user_bo;
+       struct ttm_base_object *base = *p_base;
+       struct ttm_buffer_object *bo;
+
+       *p_base = NULL;
+
+       if (unlikely(base == NULL))
+               return;
+
+       vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
+       bo = &vmw_user_bo->dma.base;
+       ttm_bo_unref(&bo);
+}
+
+int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       union drm_vmw_alloc_dmabuf_arg *arg =
+           (union drm_vmw_alloc_dmabuf_arg *)data;
+       struct drm_vmw_alloc_dmabuf_req *req = &arg->req;
+       struct drm_vmw_dmabuf_rep *rep = &arg->rep;
+       struct vmw_user_dma_buffer *vmw_user_bo;
+       struct ttm_buffer_object *tmp;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+       int ret;
+
+       vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
+       if (unlikely(vmw_user_bo == NULL))
+               return -ENOMEM;
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0)) {
+               kfree(vmw_user_bo);
+               return ret;
+       }
+
+       ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size,
+                             &vmw_vram_placement, true,
+                             &vmw_user_dmabuf_destroy);
+       if (unlikely(ret != 0))
+               return ret;
+
+       tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
+       ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
+                                  &vmw_user_bo->base,
+                                  false,
+                                  ttm_buffer_type,
+                                  &vmw_user_dmabuf_release, NULL);
+       if (unlikely(ret != 0)) {
+               ttm_bo_unref(&tmp);
+       } else {
+               rep->handle = vmw_user_bo->base.hash.key;
+               rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
+               rep->cur_gmr_id = vmw_user_bo->base.hash.key;
+               rep->cur_gmr_offset = 0;
+       }
+       ttm_bo_unref(&tmp);
+
+       ttm_read_unlock(&vmaster->lock);
+
+       return 0;
+}
+
+int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
+{
+       struct drm_vmw_unref_dmabuf_arg *arg =
+           (struct drm_vmw_unref_dmabuf_arg *)data;
+
+       return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+                                        arg->handle,
+                                        TTM_REF_USAGE);
+}
+
+uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
+                                 uint32_t cur_validate_node)
+{
+       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+
+       if (likely(vmw_bo->on_validate_list))
+               return vmw_bo->cur_validate_node;
+
+       vmw_bo->cur_validate_node = cur_validate_node;
+       vmw_bo->on_validate_list = true;
+
+       return cur_validate_node;
+}
+
+void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo)
+{
+       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+
+       vmw_bo->on_validate_list = false;
+}
+
+uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo)
+{
+       struct vmw_dma_buffer *vmw_bo;
+
+       if (bo->mem.mem_type == TTM_PL_VRAM)
+               return SVGA_GMR_FRAMEBUFFER;
+
+       vmw_bo = vmw_dma_buffer(bo);
+
+       return (vmw_bo->gmr_bound) ? vmw_bo->gmr_id : SVGA_GMR_NULL;
+}
+
+void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id)
+{
+       struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+       vmw_bo->gmr_bound = true;
+       vmw_bo->gmr_id = id;
+}
+
+int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
+                          uint32_t handle, struct vmw_dma_buffer **out)
+{
+       struct vmw_user_dma_buffer *vmw_user_bo;
+       struct ttm_base_object *base;
+
+       base = ttm_base_object_lookup(tfile, handle);
+       if (unlikely(base == NULL)) {
+               printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
+                      (unsigned long)handle);
+               return -ESRCH;
+       }
+
+       if (unlikely(base->object_type != ttm_buffer_type)) {
+               ttm_base_object_unref(&base);
+               printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
+                      (unsigned long)handle);
+               return -EINVAL;
+       }
+
+       vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
+       (void)ttm_bo_reference(&vmw_user_bo->dma.base);
+       ttm_base_object_unref(&base);
+       *out = &vmw_user_bo->dma;
+
+       return 0;
+}
+
+/**
+ * TODO: Implement a gmr id eviction mechanism. Currently we just fail
+ * when we're out of ids, causing GMR space to be allocated
+ * out of VRAM.
+ */
+
+int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
+{
+       struct ttm_bo_global *glob = dev_priv->bdev.glob;
+       int id;
+       int ret;
+
+       do {
+               if (unlikely(ida_pre_get(&dev_priv->gmr_ida, GFP_KERNEL) == 0))
+                       return -ENOMEM;
+
+               spin_lock(&glob->lru_lock);
+               ret = ida_get_new(&dev_priv->gmr_ida, &id);
+               spin_unlock(&glob->lru_lock);
+       } while (ret == -EAGAIN);
+
+       if (unlikely(ret != 0))
+               return ret;
+
+       if (unlikely(id >= dev_priv->max_gmr_ids)) {
+               spin_lock(&glob->lru_lock);
+               ida_remove(&dev_priv->gmr_ida, id);
+               spin_unlock(&glob->lru_lock);
+               return -EBUSY;
+       }
+
+       *p_id = (uint32_t) id;
+       return 0;
+}
+
+/*
+ * Stream managment
+ */
+
+static void vmw_stream_destroy(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct vmw_stream *stream;
+       int ret;
+
+       DRM_INFO("%s: unref\n", __func__);
+       stream = container_of(res, struct vmw_stream, res);
+
+       ret = vmw_overlay_unref(dev_priv, stream->stream_id);
+       WARN_ON(ret != 0);
+}
+
+static int vmw_stream_init(struct vmw_private *dev_priv,
+                          struct vmw_stream *stream,
+                          void (*res_free) (struct vmw_resource *res))
+{
+       struct vmw_resource *res = &stream->res;
+       int ret;
+
+       ret = vmw_resource_init(dev_priv, res, &dev_priv->stream_idr,
+                               VMW_RES_STREAM, res_free);
+
+       if (unlikely(ret != 0)) {
+               if (res_free == NULL)
+                       kfree(stream);
+               else
+                       res_free(&stream->res);
+               return ret;
+       }
+
+       ret = vmw_overlay_claim(dev_priv, &stream->stream_id);
+       if (ret) {
+               vmw_resource_unreference(&res);
+               return ret;
+       }
+
+       DRM_INFO("%s: claimed\n", __func__);
+
+       vmw_resource_activate(&stream->res, vmw_stream_destroy);
+       return 0;
+}
+
+/**
+ * User-space context management:
+ */
+
+static void vmw_user_stream_free(struct vmw_resource *res)
+{
+       struct vmw_user_stream *stream =
+           container_of(res, struct vmw_user_stream, stream.res);
+
+       kfree(stream);
+}
+
+/**
+ * This function is called when user space has no more references on the
+ * base object. It releases the base-object's reference on the resource object.
+ */
+
+static void vmw_user_stream_base_release(struct ttm_base_object **p_base)
+{
+       struct ttm_base_object *base = *p_base;
+       struct vmw_user_stream *stream =
+           container_of(base, struct vmw_user_stream, base);
+       struct vmw_resource *res = &stream->stream.res;
+
+       *p_base = NULL;
+       vmw_resource_unreference(&res);
+}
+
+int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_resource *res;
+       struct vmw_user_stream *stream;
+       struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret = 0;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, arg->stream_id);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_stream_free) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       stream = container_of(res, struct vmw_user_stream, stream.res);
+       if (stream->base.tfile != tfile) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ttm_ref_object_base_unref(tfile, stream->base.hash.key, TTM_REF_USAGE);
+out:
+       vmw_resource_unreference(&res);
+       return ret;
+}
+
+int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_user_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
+       struct vmw_resource *res;
+       struct vmw_resource *tmp;
+       struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret;
+
+       if (unlikely(stream == NULL))
+               return -ENOMEM;
+
+       res = &stream->stream.res;
+       stream->base.shareable = false;
+       stream->base.tfile = NULL;
+
+       ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free);
+       if (unlikely(ret != 0))
+               return ret;
+
+       tmp = vmw_resource_reference(res);
+       ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM,
+                                  &vmw_user_stream_base_release, NULL);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&tmp);
+               goto out_err;
+       }
+
+       arg->stream_id = res->id;
+out_err:
+       vmw_resource_unreference(&res);
+       return ret;
+}
+
+int vmw_user_stream_lookup(struct vmw_private *dev_priv,
+                          struct ttm_object_file *tfile,
+                          uint32_t *inout_id, struct vmw_resource **out)
+{
+       struct vmw_user_stream *stream;
+       struct vmw_resource *res;
+       int ret;
+
+       res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, *inout_id);
+       if (unlikely(res == NULL))
+               return -EINVAL;
+
+       if (res->res_free != &vmw_user_stream_free) {
+               ret = -EINVAL;
+               goto err_ref;
+       }
+
+       stream = container_of(res, struct vmw_user_stream, stream.res);
+       if (stream->base.tfile != tfile) {
+               ret = -EPERM;
+               goto err_ref;
+       }
+
+       *inout_id = stream->stream.stream_id;
+       *out = res;
+       return 0;
+err_ref:
+       vmw_resource_unreference(&res);
+       return ret;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
new file mode 100644 (file)
index 0000000..e3df4ad
--- /dev/null
@@ -0,0 +1,99 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct vmw_private *dev_priv;
+
+       if (unlikely(vma->vm_pgoff < VMWGFX_FILE_PAGE_OFFSET)) {
+               if (vmw_fifo_mmap(filp, vma) == 0)
+                       return 0;
+               return drm_mmap(filp, vma);
+       }
+
+       file_priv = (struct drm_file *)filp->private_data;
+       dev_priv = vmw_priv(file_priv->minor->dev);
+       return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
+}
+
+static int vmw_ttm_mem_global_init(struct ttm_global_reference *ref)
+{
+       DRM_INFO("global init.\n");
+       return ttm_mem_global_init(ref->object);
+}
+
+static void vmw_ttm_mem_global_release(struct ttm_global_reference *ref)
+{
+       ttm_mem_global_release(ref->object);
+}
+
+int vmw_ttm_global_init(struct vmw_private *dev_priv)
+{
+       struct ttm_global_reference *global_ref;
+       int ret;
+
+       global_ref = &dev_priv->mem_global_ref;
+       global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+       global_ref->size = sizeof(struct ttm_mem_global);
+       global_ref->init = &vmw_ttm_mem_global_init;
+       global_ref->release = &vmw_ttm_mem_global_release;
+
+       ret = ttm_global_item_ref(global_ref);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed setting up TTM memory accounting.\n");
+               return ret;
+       }
+
+       dev_priv->bo_global_ref.mem_glob =
+               dev_priv->mem_global_ref.object;
+       global_ref = &dev_priv->bo_global_ref.ref;
+       global_ref->global_type = TTM_GLOBAL_TTM_BO;
+       global_ref->size = sizeof(struct ttm_bo_global);
+       global_ref->init = &ttm_bo_global_init;
+       global_ref->release = &ttm_bo_global_release;
+               ret = ttm_global_item_ref(global_ref);
+
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed setting up TTM buffer objects.\n");
+               goto out_no_bo;
+       }
+
+       return 0;
+out_no_bo:
+       ttm_global_item_unref(&dev_priv->mem_global_ref);
+       return ret;
+}
+
+void vmw_ttm_global_release(struct vmw_private *dev_priv)
+{
+       ttm_global_item_unref(&dev_priv->bo_global_ref.ref);
+       ttm_global_item_unref(&dev_priv->mem_global_ref);
+}
index 54e174d28234600c49f8845f94c6fcfb7162aa03..093f57af32d3d9614973372af2e6abce81268706 100644 (file)
@@ -99,6 +99,8 @@ source "drivers/staging/p9auth/Kconfig"
 
 source "drivers/staging/line6/Kconfig"
 
+source "drivers/gpu/drm/vmwgfx/Kconfig"
+
 source "drivers/gpu/drm/radeon/Kconfig"
 
 source "drivers/gpu/drm/nouveau/Kconfig"
index cfa6af43c9ea49b0d9e00768f1b0a2027b9dd699..bd3a1c2fbdb40f342d026c766d90eaecc891fa23 100644 (file)
@@ -7,5 +7,6 @@ unifdef-y += r128_drm.h
 unifdef-y += radeon_drm.h
 unifdef-y += sis_drm.h
 unifdef-y += savage_drm.h
+unifdef-y += vmwgfx_drm.h
 unifdef-y += via_drm.h
 unifdef-y += nouveau_drm.h
index 703ca4db0a297615f84064ee736ddd191b5f3b83..0d9db099978b778e14301f04dac41a197d7ec88a 100644 (file)
@@ -77,7 +77,11 @@ enum ttm_object_type {
        ttm_buffer_type,
        ttm_lock_type,
        ttm_driver_type0 = 256,
-       ttm_driver_type1
+       ttm_driver_type1,
+       ttm_driver_type2,
+       ttm_driver_type3,
+       ttm_driver_type4,
+       ttm_driver_type5
 };
 
 struct ttm_object_file;
diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h
new file mode 100644 (file)
index 0000000..2be7e12
--- /dev/null
@@ -0,0 +1,574 @@
+/**************************************************************************
+ *
+ * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef __VMWGFX_DRM_H__
+#define __VMWGFX_DRM_H__
+
+#define DRM_VMW_MAX_SURFACE_FACES 6
+#define DRM_VMW_MAX_MIP_LEVELS 24
+
+#define DRM_VMW_EXT_NAME_LEN 128
+
+#define DRM_VMW_GET_PARAM            0
+#define DRM_VMW_ALLOC_DMABUF         1
+#define DRM_VMW_UNREF_DMABUF         2
+#define DRM_VMW_CURSOR_BYPASS        3
+/* guarded by DRM_VMW_PARAM_NUM_STREAMS != 0*/
+#define DRM_VMW_CONTROL_STREAM       4
+#define DRM_VMW_CLAIM_STREAM         5
+#define DRM_VMW_UNREF_STREAM         6
+/* guarded by DRM_VMW_PARAM_3D == 1 */
+#define DRM_VMW_CREATE_CONTEXT       7
+#define DRM_VMW_UNREF_CONTEXT        8
+#define DRM_VMW_CREATE_SURFACE       9
+#define DRM_VMW_UNREF_SURFACE        10
+#define DRM_VMW_REF_SURFACE          11
+#define DRM_VMW_EXECBUF              12
+#define DRM_VMW_FIFO_DEBUG           13
+#define DRM_VMW_FENCE_WAIT           14
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_GET_PARAM - get device information.
+ *
+ * DRM_VMW_PARAM_FIFO_OFFSET:
+ * Offset to use to map the first page of the FIFO read-only.
+ * The fifo is mapped using the mmap() system call on the drm device.
+ *
+ * DRM_VMW_PARAM_OVERLAY_IOCTL:
+ * Does the driver support the overlay ioctl.
+ */
+
+#define DRM_VMW_PARAM_NUM_STREAMS      0
+#define DRM_VMW_PARAM_NUM_FREE_STREAMS 1
+#define DRM_VMW_PARAM_3D               2
+#define DRM_VMW_PARAM_FIFO_OFFSET      3
+
+
+/**
+ * struct drm_vmw_getparam_arg
+ *
+ * @value: Returned value. //Out
+ * @param: Parameter to query. //In.
+ *
+ * Argument to the DRM_VMW_GET_PARAM Ioctl.
+ */
+
+struct drm_vmw_getparam_arg {
+       uint64_t value;
+       uint32_t param;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_EXTENSION - Query device extensions.
+ */
+
+/**
+ * struct drm_vmw_extension_rep
+ *
+ * @exists: The queried extension exists.
+ * @driver_ioctl_offset: Ioctl number of the first ioctl in the extension.
+ * @driver_sarea_offset: Offset to any space in the DRI SAREA
+ * used by the extension.
+ * @major: Major version number of the extension.
+ * @minor: Minor version number of the extension.
+ * @pl: Patch level version number of the extension.
+ *
+ * Output argument to the DRM_VMW_EXTENSION Ioctl.
+ */
+
+struct drm_vmw_extension_rep {
+       int32_t exists;
+       uint32_t driver_ioctl_offset;
+       uint32_t driver_sarea_offset;
+       uint32_t major;
+       uint32_t minor;
+       uint32_t pl;
+       uint32_t pad64;
+};
+
+/**
+ * union drm_vmw_extension_arg
+ *
+ * @extension - Ascii name of the extension to be queried. //In
+ * @rep - Reply as defined above. //Out
+ *
+ * Argument to the DRM_VMW_EXTENSION Ioctl.
+ */
+
+union drm_vmw_extension_arg {
+       char extension[DRM_VMW_EXT_NAME_LEN];
+       struct drm_vmw_extension_rep rep;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CREATE_CONTEXT - Create a host context.
+ *
+ * Allocates a device unique context id, and queues a create context command
+ * for the host. Does not wait for host completion.
+ */
+
+/**
+ * struct drm_vmw_context_arg
+ *
+ * @cid: Device unique context ID.
+ *
+ * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl.
+ * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl.
+ */
+
+struct drm_vmw_context_arg {
+       int32_t cid;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_CONTEXT - Create a host context.
+ *
+ * Frees a global context id, and queues a destroy host command for the host.
+ * Does not wait for host completion. The context ID can be used directly
+ * in the command stream and shows up as the same context ID on the host.
+ */
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CREATE_SURFACE - Create a host suface.
+ *
+ * Allocates a device unique surface id, and queues a create surface command
+ * for the host. Does not wait for host completion. The surface ID can be
+ * used directly in the command stream and shows up as the same surface
+ * ID on the host.
+ */
+
+/**
+ * struct drm_wmv_surface_create_req
+ *
+ * @flags: Surface flags as understood by the host.
+ * @format: Surface format as understood by the host.
+ * @mip_levels: Number of mip levels for each face.
+ * An unused face should have 0 encoded.
+ * @size_addr: Address of a user-space array of sruct drm_vmw_size
+ * cast to an uint64_t for 32-64 bit compatibility.
+ * The size of the array should equal the total number of mipmap levels.
+ * @shareable: Boolean whether other clients (as identified by file descriptors)
+ * may reference this surface.
+ *
+ * Input data to the DRM_VMW_CREATE_SURFACE Ioctl.
+ * Output data from the DRM_VMW_REF_SURFACE Ioctl.
+ */
+
+struct drm_vmw_surface_create_req {
+       uint32_t flags;
+       uint32_t format;
+       uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
+       uint64_t size_addr;
+       int32_t shareable;
+       uint32_t pad64;
+};
+
+/**
+ * struct drm_wmv_surface_arg
+ *
+ * @sid: Surface id of created surface or surface to destroy or reference.
+ *
+ * Output data from the DRM_VMW_CREATE_SURFACE Ioctl.
+ * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl.
+ * Input argument to the DRM_VMW_REF_SURFACE Ioctl.
+ */
+
+struct drm_vmw_surface_arg {
+       int32_t sid;
+       uint32_t pad64;
+};
+
+/**
+ * struct drm_vmw_size ioctl.
+ *
+ * @width - mip level width
+ * @height - mip level height
+ * @depth - mip level depth
+ *
+ * Description of a mip level.
+ * Input data to the DRM_WMW_CREATE_SURFACE Ioctl.
+ */
+
+struct drm_vmw_size {
+       uint32_t width;
+       uint32_t height;
+       uint32_t depth;
+       uint32_t pad64;
+};
+
+/**
+ * union drm_vmw_surface_create_arg
+ *
+ * @rep: Output data as described above.
+ * @req: Input data as described above.
+ *
+ * Argument to the DRM_VMW_CREATE_SURFACE Ioctl.
+ */
+
+union drm_vmw_surface_create_arg {
+       struct drm_vmw_surface_arg rep;
+       struct drm_vmw_surface_create_req req;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_REF_SURFACE - Reference a host surface.
+ *
+ * Puts a reference on a host surface with a give sid, as previously
+ * returned by the DRM_VMW_CREATE_SURFACE ioctl.
+ * A reference will make sure the surface isn't destroyed while we hold
+ * it and will allow the calling client to use the surface ID in the command
+ * stream.
+ *
+ * On successful return, the Ioctl returns the surface information given
+ * in the DRM_VMW_CREATE_SURFACE ioctl.
+ */
+
+/**
+ * union drm_vmw_surface_reference_arg
+ *
+ * @rep: Output data as described above.
+ * @req: Input data as described above.
+ *
+ * Argument to the DRM_VMW_REF_SURFACE Ioctl.
+ */
+
+union drm_vmw_surface_reference_arg {
+       struct drm_vmw_surface_create_req rep;
+       struct drm_vmw_surface_arg req;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_SURFACE - Unreference a host surface.
+ *
+ * Clear a reference previously put on a host surface.
+ * When all references are gone, including the one implicitly placed
+ * on creation,
+ * a destroy surface command will be queued for the host.
+ * Does not wait for completion.
+ */
+
+/*************************************************************************/
+/**
+ * DRM_VMW_EXECBUF
+ *
+ * Submit a command buffer for execution on the host, and return a
+ * fence sequence that when signaled, indicates that the command buffer has
+ * executed.
+ */
+
+/**
+ * struct drm_vmw_execbuf_arg
+ *
+ * @commands: User-space address of a command buffer cast to an uint64_t.
+ * @command-size: Size in bytes of the command buffer.
+ * @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an
+ * uint64_t.
+ *
+ * Argument to the DRM_VMW_EXECBUF Ioctl.
+ */
+
+struct drm_vmw_execbuf_arg {
+       uint64_t commands;
+       uint32_t command_size;
+       uint32_t pad64;
+       uint64_t fence_rep;
+};
+
+/**
+ * struct drm_vmw_fence_rep
+ *
+ * @fence_seq: Fence sequence associated with a command submission.
+ * @error: This member should've been set to -EFAULT on submission.
+ * The following actions should be take on completion:
+ * error == -EFAULT: Fence communication failed. The host is synchronized.
+ * Use the last fence id read from the FIFO fence register.
+ * error != 0 && error != -EFAULT:
+ * Fence submission failed. The host is synchronized. Use the fence_seq member.
+ * error == 0: All is OK, The host may not be synchronized.
+ * Use the fence_seq member.
+ *
+ * Input / Output data to the DRM_VMW_EXECBUF Ioctl.
+ */
+
+struct drm_vmw_fence_rep {
+       uint64_t fence_seq;
+       int32_t error;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_ALLOC_DMABUF
+ *
+ * Allocate a DMA buffer that is visible also to the host.
+ * NOTE: The buffer is
+ * identified by a handle and an offset, which are private to the guest, but
+ * useable in the command stream. The guest kernel may translate these
+ * and patch up the command stream accordingly. In the future, the offset may
+ * be zero at all times, or it may disappear from the interface before it is
+ * fixed.
+ *
+ * The DMA buffer may stay user-space mapped in the guest at all times,
+ * and is thus suitable for sub-allocation.
+ *
+ * DMA buffers are mapped using the mmap() syscall on the drm device.
+ */
+
+/**
+ * struct drm_vmw_alloc_dmabuf_req
+ *
+ * @size: Required minimum size of the buffer.
+ *
+ * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl.
+ */
+
+struct drm_vmw_alloc_dmabuf_req {
+       uint32_t size;
+       uint32_t pad64;
+};
+
+/**
+ * struct drm_vmw_dmabuf_rep
+ *
+ * @map_handle: Offset to use in the mmap() call used to map the buffer.
+ * @handle: Handle unique to this buffer. Used for unreferencing.
+ * @cur_gmr_id: GMR id to use in the command stream when this buffer is
+ * referenced. See not above.
+ * @cur_gmr_offset: Offset to use in the command stream when this buffer is
+ * referenced. See note above.
+ *
+ * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl.
+ */
+
+struct drm_vmw_dmabuf_rep {
+       uint64_t map_handle;
+       uint32_t handle;
+       uint32_t cur_gmr_id;
+       uint32_t cur_gmr_offset;
+       uint32_t pad64;
+};
+
+/**
+ * union drm_vmw_dmabuf_arg
+ *
+ * @req: Input data as described above.
+ * @rep: Output data as described above.
+ *
+ * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl.
+ */
+
+union drm_vmw_alloc_dmabuf_arg {
+       struct drm_vmw_alloc_dmabuf_req req;
+       struct drm_vmw_dmabuf_rep rep;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_DMABUF - Free a DMA buffer.
+ *
+ */
+
+/**
+ * struct drm_vmw_unref_dmabuf_arg
+ *
+ * @handle: Handle indicating what buffer to free. Obtained from the
+ * DRM_VMW_ALLOC_DMABUF Ioctl.
+ *
+ * Argument to the DRM_VMW_UNREF_DMABUF Ioctl.
+ */
+
+struct drm_vmw_unref_dmabuf_arg {
+       uint32_t handle;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FIFO_DEBUG - Get last FIFO submission.
+ *
+ * This IOCTL copies the last FIFO submission directly out of the FIFO buffer.
+ */
+
+/**
+ * struct drm_vmw_fifo_debug_arg
+ *
+ * @debug_buffer: User space address of a debug_buffer cast to an uint64_t //In
+ * @debug_buffer_size: Size in bytes of debug buffer //In
+ * @used_size: Number of bytes copied to the buffer // Out
+ * @did_not_fit: Boolean indicating that the fifo contents did not fit. //Out
+ *
+ * Argument to the DRM_VMW_FIFO_DEBUG Ioctl.
+ */
+
+struct drm_vmw_fifo_debug_arg {
+       uint64_t debug_buffer;
+       uint32_t debug_buffer_size;
+       uint32_t used_size;
+       int32_t did_not_fit;
+       uint32_t pad64;
+};
+
+struct drm_vmw_fence_wait_arg {
+       uint64_t sequence;
+       uint64_t kernel_cookie;
+       int32_t cookie_valid;
+       int32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams.
+ *
+ * This IOCTL controls the overlay units of the svga device.
+ * The SVGA overlay units does not work like regular hardware units in
+ * that they do not automaticaly read back the contents of the given dma
+ * buffer. But instead only read back for each call to this ioctl, and
+ * at any point between this call being made and a following call that
+ * either changes the buffer or disables the stream.
+ */
+
+/**
+ * struct drm_vmw_rect
+ *
+ * Defines a rectangle. Used in the overlay ioctl to define
+ * source and destination rectangle.
+ */
+
+struct drm_vmw_rect {
+       int32_t x;
+       int32_t y;
+       uint32_t w;
+       uint32_t h;
+};
+
+/**
+ * struct drm_vmw_control_stream_arg
+ *
+ * @stream_id: Stearm to control
+ * @enabled: If false all following arguments are ignored.
+ * @handle: Handle to buffer for getting data from.
+ * @format: Format of the overlay as understood by the host.
+ * @width: Width of the overlay.
+ * @height: Height of the overlay.
+ * @size: Size of the overlay in bytes.
+ * @pitch: Array of pitches, the two last are only used for YUV12 formats.
+ * @offset: Offset from start of dma buffer to overlay.
+ * @src: Source rect, must be within the defined area above.
+ * @dst: Destination rect, x and y may be negative.
+ *
+ * Argument to the DRM_VMW_CONTROL_STREAM Ioctl.
+ */
+
+struct drm_vmw_control_stream_arg {
+       uint32_t stream_id;
+       uint32_t enabled;
+
+       uint32_t flags;
+       uint32_t color_key;
+
+       uint32_t handle;
+       uint32_t offset;
+       int32_t format;
+       uint32_t size;
+       uint32_t width;
+       uint32_t height;
+       uint32_t pitch[3];
+
+       uint32_t pad64;
+       struct drm_vmw_rect src;
+       struct drm_vmw_rect dst;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CURSOR_BYPASS - Give extra information about cursor bypass.
+ *
+ */
+
+#define DRM_VMW_CURSOR_BYPASS_ALL    (1 << 0)
+#define DRM_VMW_CURSOR_BYPASS_FLAGS       (1)
+
+/**
+ * struct drm_vmw_cursor_bypass_arg
+ *
+ * @flags: Flags.
+ * @crtc_id: Crtc id, only used if DMR_CURSOR_BYPASS_ALL isn't passed.
+ * @xpos: X position of cursor.
+ * @ypos: Y position of cursor.
+ * @xhot: X hotspot.
+ * @yhot: Y hotspot.
+ *
+ * Argument to the DRM_VMW_CURSOR_BYPASS Ioctl.
+ */
+
+struct drm_vmw_cursor_bypass_arg {
+       uint32_t flags;
+       uint32_t crtc_id;
+       int32_t xpos;
+       int32_t ypos;
+       int32_t xhot;
+       int32_t yhot;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CLAIM_STREAM - Claim a single stream.
+ */
+
+/**
+ * struct drm_vmw_context_arg
+ *
+ * @stream_id: Device unique context ID.
+ *
+ * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl.
+ * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl.
+ */
+
+struct drm_vmw_stream_arg {
+       uint32_t stream_id;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_STREAM - Unclaim a stream.
+ *
+ * Return a single stream that was claimed by this process. Also makes
+ * sure that the stream has been stopped.
+ */
+
+#endif