drm/vmwgfx: Reserve first part of VRAM for framebuffer.
authorThomas Hellstrom <thellstrom@vmware.com>
Fri, 28 May 2010 09:22:00 +0000 (11:22 +0200)
committerDave Airlie <airlied@redhat.com>
Mon, 31 May 2010 23:37:28 +0000 (09:37 +1000)
The host may be touching this part of VRAM at modesetting,
even if we never use it ourselves, since we blit screen updates from 3D
surfaces. Make sure no DMA buffers are placed in this part of VRAM.

V2: Fix an error check in vmw_surface_dmabuf_pin().

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c

index c748207..250282f 100644 (file)
@@ -30,6 +30,8 @@
 /* Might need a hrtimer here? */
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
 
+static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb);
+static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb);
 
 void vmw_display_unit_cleanup(struct vmw_display_unit *du)
 {
@@ -326,6 +328,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb,
 struct vmw_framebuffer_surface {
        struct vmw_framebuffer base;
        struct vmw_surface *surface;
+       struct vmw_dma_buffer *buffer;
        struct delayed_work d_work;
        struct mutex work_lock;
        bool present_fs;
@@ -500,8 +503,8 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
        vfbs->base.base.depth = 24;
        vfbs->base.base.width = width;
        vfbs->base.base.height = height;
-       vfbs->base.pin = NULL;
-       vfbs->base.unpin = NULL;
+       vfbs->base.pin = &vmw_surface_dmabuf_pin;
+       vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
        vfbs->surface = surface;
        mutex_init(&vfbs->work_lock);
        INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
@@ -589,6 +592,40 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
        .create_handle = vmw_framebuffer_create_handle,
 };
 
+static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb)
+{
+       struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
+       struct vmw_framebuffer_surface *vfbs =
+               vmw_framebuffer_to_vfbs(&vfb->base);
+       unsigned long size = vfbs->base.base.pitch * vfbs->base.base.height;
+       int ret;
+
+       vfbs->buffer = kzalloc(sizeof(*vfbs->buffer), GFP_KERNEL);
+       if (unlikely(vfbs->buffer == NULL))
+               return -ENOMEM;
+
+       vmw_overlay_pause_all(dev_priv);
+       ret = vmw_dmabuf_init(dev_priv, vfbs->buffer, size,
+                              &vmw_vram_ne_placement,
+                              false, &vmw_dmabuf_bo_free);
+       vmw_overlay_resume_all(dev_priv);
+
+       return ret;
+}
+
+static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb)
+{
+       struct ttm_buffer_object *bo;
+       struct vmw_framebuffer_surface *vfbs =
+               vmw_framebuffer_to_vfbs(&vfb->base);
+
+       bo = &vfbs->buffer->base;
+       ttm_bo_unref(&bo);
+       vfbs->buffer = NULL;
+
+       return 0;
+}
+
 static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
 {
        struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);