Merge tag 'drm-fixes-for-v4.7-rc8-vmware' of git://people.freedesktop.org/~airlied/linux

Pull drm vmware fixes from Dave Airlie:
 "These are some fixes for the vmware graphics driver, that fix some
  black screen issues on at least Ubuntu 16.04, I think VMware would
  like to get these in so stable can pick them up ASAP"

* tag 'drm-fixes-for-v4.7-rc8-vmware' of git://people.freedesktop.org/~airlied/linux:
  drm/vmwgfx: Fix error paths when mapping framebuffer
  drm/vmwgfx: Fix corner case screen target management
  drm/vmwgfx: Delay pinning fbdev framebuffer until after mode set
  drm/vmwgfx: Check pin count before attempting to move a buffer
  drm/ttm: Make ttm_bo_mem_compat available
  drm/vmwgfx: Add an option to change assumed FB bpp
  drm/vmwgfx: Work around mode set failure in 2D VMs
  drm/vmwgfx: Add a check to handle host message failure
This commit is contained in:
Linus Torvalds 2016-07-15 15:16:13 +09:00
commit 1f027f691e
9 changed files with 88 additions and 39 deletions

View File

@ -1034,9 +1034,9 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
return ret; return ret;
} }
static bool ttm_bo_mem_compat(struct ttm_placement *placement, bool ttm_bo_mem_compat(struct ttm_placement *placement,
struct ttm_mem_reg *mem, struct ttm_mem_reg *mem,
uint32_t *new_flags) uint32_t *new_flags)
{ {
int i; int i;
@ -1068,6 +1068,7 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement,
return false; return false;
} }
EXPORT_SYMBOL(ttm_bo_mem_compat);
int ttm_bo_validate(struct ttm_buffer_object *bo, int ttm_bo_validate(struct ttm_buffer_object *bo,
struct ttm_placement *placement, struct ttm_placement *placement,

View File

@ -49,6 +49,7 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv,
{ {
struct ttm_buffer_object *bo = &buf->base; struct ttm_buffer_object *bo = &buf->base;
int ret; int ret;
uint32_t new_flags;
ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
@ -60,7 +61,12 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv,
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto err; goto err;
ret = ttm_bo_validate(bo, placement, interruptible, false); if (buf->pin_count > 0)
ret = ttm_bo_mem_compat(placement, &bo->mem,
&new_flags) == true ? 0 : -EINVAL;
else
ret = ttm_bo_validate(bo, placement, interruptible, false);
if (!ret) if (!ret)
vmw_bo_pin_reserved(buf, true); vmw_bo_pin_reserved(buf, true);
@ -91,6 +97,7 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv,
{ {
struct ttm_buffer_object *bo = &buf->base; struct ttm_buffer_object *bo = &buf->base;
int ret; int ret;
uint32_t new_flags;
ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
@ -102,6 +109,12 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv,
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto err; goto err;
if (buf->pin_count > 0) {
ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem,
&new_flags) == true ? 0 : -EINVAL;
goto out_unreserve;
}
ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible,
false); false);
if (likely(ret == 0) || ret == -ERESTARTSYS) if (likely(ret == 0) || ret == -ERESTARTSYS)
@ -161,6 +174,7 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv,
struct ttm_placement placement; struct ttm_placement placement;
struct ttm_place place; struct ttm_place place;
int ret = 0; int ret = 0;
uint32_t new_flags;
place = vmw_vram_placement.placement[0]; place = vmw_vram_placement.placement[0];
place.lpfn = bo->num_pages; place.lpfn = bo->num_pages;
@ -185,10 +199,15 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv,
*/ */
if (bo->mem.mem_type == TTM_PL_VRAM && if (bo->mem.mem_type == TTM_PL_VRAM &&
bo->mem.start < bo->num_pages && bo->mem.start < bo->num_pages &&
bo->mem.start > 0) bo->mem.start > 0 &&
buf->pin_count == 0)
(void) ttm_bo_validate(bo, &vmw_sys_placement, false, false); (void) ttm_bo_validate(bo, &vmw_sys_placement, false, false);
ret = ttm_bo_validate(bo, &placement, interruptible, false); if (buf->pin_count > 0)
ret = ttm_bo_mem_compat(&placement, &bo->mem,
&new_flags) == true ? 0 : -EINVAL;
else
ret = ttm_bo_validate(bo, &placement, interruptible, false);
/* For some reason we didn't end up at the start of vram */ /* For some reason we didn't end up at the start of vram */
WARN_ON(ret == 0 && bo->offset != 0); WARN_ON(ret == 0 && bo->offset != 0);

View File

@ -233,6 +233,7 @@ static int vmw_force_iommu;
static int vmw_restrict_iommu; static int vmw_restrict_iommu;
static int vmw_force_coherent; static int vmw_force_coherent;
static int vmw_restrict_dma_mask; static int vmw_restrict_dma_mask;
static int vmw_assume_16bpp;
static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static void vmw_master_init(struct vmw_master *); static void vmw_master_init(struct vmw_master *);
@ -249,6 +250,8 @@ MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
module_param_named(force_coherent, vmw_force_coherent, int, 0600); module_param_named(force_coherent, vmw_force_coherent, int, 0600);
MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU"); MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU");
module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600); module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600);
MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes");
module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600);
static void vmw_print_capabilities(uint32_t capabilities) static void vmw_print_capabilities(uint32_t capabilities)
@ -660,6 +663,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->vram_start = pci_resource_start(dev->pdev, 1); dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
dev_priv->assume_16bpp = !!vmw_assume_16bpp;
dev_priv->enable_fb = enable_fbdev; dev_priv->enable_fb = enable_fbdev;
vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
@ -706,6 +711,13 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
vmw_read(dev_priv, vmw_read(dev_priv,
SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB);
/*
* Workaround for low memory 2D VMs to compensate for the
* allocation taken by fbdev
*/
if (!(dev_priv->capabilities & SVGA_CAP_3D))
mem_size *= 2;
dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE; dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE;
dev_priv->prim_bb_mem = dev_priv->prim_bb_mem =
vmw_read(dev_priv, vmw_read(dev_priv,

View File

@ -386,6 +386,7 @@ struct vmw_private {
spinlock_t hw_lock; spinlock_t hw_lock;
spinlock_t cap_lock; spinlock_t cap_lock;
bool has_dx; bool has_dx;
bool assume_16bpp;
/* /*
* VGA registers. * VGA registers.

View File

@ -517,28 +517,6 @@ static int vmw_fb_kms_framebuffer(struct fb_info *info)
par->set_fb = &vfb->base; par->set_fb = &vfb->base;
if (!par->bo_ptr) {
/*
* Pin before mapping. Since we don't know in what placement
* to pin, call into KMS to do it for us.
*/
ret = vfb->pin(vfb);
if (ret) {
DRM_ERROR("Could not pin the fbdev framebuffer.\n");
return ret;
}
ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
par->vmw_bo->base.num_pages, &par->map);
if (ret) {
vfb->unpin(vfb);
DRM_ERROR("Could not map the fbdev framebuffer.\n");
return ret;
}
par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
}
return 0; return 0;
} }
@ -601,6 +579,31 @@ static int vmw_fb_set_par(struct fb_info *info)
if (ret) if (ret)
goto out_unlock; goto out_unlock;
if (!par->bo_ptr) {
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb);
/*
* Pin before mapping. Since we don't know in what placement
* to pin, call into KMS to do it for us.
*/
ret = vfb->pin(vfb);
if (ret) {
DRM_ERROR("Could not pin the fbdev framebuffer.\n");
goto out_unlock;
}
ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
par->vmw_bo->base.num_pages, &par->map);
if (ret) {
vfb->unpin(vfb);
DRM_ERROR("Could not map the fbdev framebuffer.\n");
goto out_unlock;
}
par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
}
vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
par->set_fb->width, par->set_fb->height); par->set_fb->width, par->set_fb->height);

View File

@ -1553,14 +1553,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
}; };
int i; int i;
u32 assumed_bpp = 2; u32 assumed_bpp = 4;
/* if (dev_priv->assume_16bpp)
* If using screen objects, then assume 32-bpp because that's what the assumed_bpp = 2;
* SVGA device is assuming
*/
if (dev_priv->active_display_unit == vmw_du_screen_object)
assumed_bpp = 4;
if (dev_priv->active_display_unit == vmw_du_screen_target) { if (dev_priv->active_display_unit == vmw_du_screen_target) {
max_width = min(max_width, dev_priv->stdu_max_width); max_width = min(max_width, dev_priv->stdu_max_width);

View File

@ -300,6 +300,9 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
break; break;
} }
if (retries == RETRIES)
return -EINVAL;
*msg_len = reply_len; *msg_len = reply_len;
*msg = reply; *msg = reply;

View File

@ -399,8 +399,10 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
WARN_ON_ONCE(!stdu->defined); WARN_ON_ONCE(!stdu->defined);
if (!vfb->dmabuf && new_fb->width == mode->hdisplay && new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
new_fb->height == mode->vdisplay)
if (new_vfbs && new_vfbs->surface->base_size.width == mode->hdisplay &&
new_vfbs->surface->base_size.height == mode->vdisplay)
new_content_type = SAME_AS_DISPLAY; new_content_type = SAME_AS_DISPLAY;
else if (vfb->dmabuf) else if (vfb->dmabuf)
new_content_type = SEPARATE_DMA; new_content_type = SEPARATE_DMA;
@ -444,7 +446,6 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
content_srf.mip_levels[0] = 1; content_srf.mip_levels[0] = 1;
content_srf.multisample_count = 0; content_srf.multisample_count = 0;
} else { } else {
new_vfbs = vmw_framebuffer_to_vfbs(new_fb);
content_srf = *new_vfbs->surface; content_srf = *new_vfbs->surface;
} }
@ -464,7 +465,6 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
return ret; return ret;
} }
} else if (new_content_type == SAME_AS_DISPLAY) { } else if (new_content_type == SAME_AS_DISPLAY) {
new_vfbs = vmw_framebuffer_to_vfbs(new_fb);
new_display_srf = vmw_surface_reference(new_vfbs->surface); new_display_srf = vmw_surface_reference(new_vfbs->surface);
} }

View File

@ -316,6 +316,20 @@ ttm_bo_reference(struct ttm_buffer_object *bo)
*/ */
extern int ttm_bo_wait(struct ttm_buffer_object *bo, extern int ttm_bo_wait(struct ttm_buffer_object *bo,
bool interruptible, bool no_wait); bool interruptible, bool no_wait);
/**
* ttm_bo_mem_compat - Check if proposed placement is compatible with a bo
*
* @placement: Return immediately if buffer is busy.
* @mem: The struct ttm_mem_reg indicating the region where the bo resides
* @new_flags: Describes compatible placement found
*
* Returns true if the placement is compatible
*/
extern bool ttm_bo_mem_compat(struct ttm_placement *placement,
struct ttm_mem_reg *mem,
uint32_t *new_flags);
/** /**
* ttm_bo_validate * ttm_bo_validate
* *