Skip to content

Commit

Permalink
drm/vmwgfx: Fix crash when unloading vmwgfx v2
Browse files Browse the repository at this point in the history
This patch fixes two issues.  One, when a surface is a proxy for a DMA
buffer, it holds an extra reference that needs to be cleared.

Two, when fbdev is enabled, we need to unpin the framebuffer before
unloading the driver.  This is done by a call to vmw_fb_off().

v2
Moved unreferencing surface to from vmw_framebuffer_surface_destroy()
to vmw_kms_new_framebuffer()

Added "struct vmw_framebuffer *vfb = NULL;" to silence a compiler
warning.

Removed error checking after calling vmw_surface/dmabuf_reference()

Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
  • Loading branch information
Sinclair Yeh authored and Thomas Hellstrom committed Aug 12, 2015
1 parent df45e9d commit 05c9501
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 24 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,7 @@ static int vmw_driver_unload(struct drm_device *dev)
drm_ht_remove(&dev_priv->ctx.res_ht);
vfree(dev_priv->ctx.cmd_bounce);
if (dev_priv->enable_fb) {
vmw_fb_off(dev_priv);
vmw_fb_close(dev_priv);
vmw_fifo_resource_dec(dev_priv);
vmw_svga_disable(dev_priv);
Expand Down
42 changes: 18 additions & 24 deletions drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,19 +539,13 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
goto out_err1;
}

if (!vmw_surface_reference(surface)) {
DRM_ERROR("failed to reference surface %p\n", surface);
ret = -EINVAL;
goto out_err2;
}

/* XXX get the first 3 from the surface info */
vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
vfbs->base.base.pitches[0] = mode_cmd->pitch;
vfbs->base.base.depth = mode_cmd->depth;
vfbs->base.base.width = mode_cmd->width;
vfbs->base.base.height = mode_cmd->height;
vfbs->surface = surface;
vfbs->surface = vmw_surface_reference(surface);
vfbs->base.user_handle = mode_cmd->handle;
vfbs->is_dmabuf_proxy = is_dmabuf_proxy;

Expand All @@ -560,13 +554,12 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
ret = drm_framebuffer_init(dev, &vfbs->base.base,
&vmw_framebuffer_surface_funcs);
if (ret)
goto out_err3;
goto out_err2;

return 0;

out_err3:
vmw_surface_unreference(&surface);
out_err2:
vmw_surface_unreference(&surface);
kfree(vfbs);
out_err1:
return ret;
Expand Down Expand Up @@ -836,32 +829,25 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
goto out_err1;
}

if (!vmw_dmabuf_reference(dmabuf)) {
DRM_ERROR("failed to reference dmabuf %p\n", dmabuf);
ret = -EINVAL;
goto out_err2;
}

vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
vfbd->base.base.pitches[0] = mode_cmd->pitch;
vfbd->base.base.depth = mode_cmd->depth;
vfbd->base.base.width = mode_cmd->width;
vfbd->base.base.height = mode_cmd->height;
vfbd->base.dmabuf = true;
vfbd->buffer = dmabuf;
vfbd->buffer = vmw_dmabuf_reference(dmabuf);
vfbd->base.user_handle = mode_cmd->handle;
*out = &vfbd->base;

ret = drm_framebuffer_init(dev, &vfbd->base.base,
&vmw_framebuffer_dmabuf_funcs);
if (ret)
goto out_err3;
goto out_err2;

return 0;

out_err3:
vmw_dmabuf_unreference(&dmabuf);
out_err2:
vmw_dmabuf_unreference(&dmabuf);
kfree(vfbd);
out_err1:
return ret;
Expand All @@ -886,7 +872,7 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
bool only_2d,
const struct drm_mode_fb_cmd *mode_cmd)
{
struct vmw_framebuffer *vfb;
struct vmw_framebuffer *vfb = NULL;
bool is_dmabuf_proxy = false;
int ret;

Expand All @@ -906,15 +892,23 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
}

/* Create the new framebuffer depending one what we have */
if (surface)
if (surface) {
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_dmabuf_proxy);
else if (dmabuf)

/*
* vmw_create_dmabuf_proxy() adds a reference that is no longer
* needed
*/
if (is_dmabuf_proxy)
vmw_surface_unreference(&surface);
} else if (dmabuf) {
ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb,
mode_cmd);
else
} else {
BUG();
}

if (ret)
return ERR_PTR(ret);
Expand Down

0 comments on commit 05c9501

Please sign in to comment.