diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 177 |
1 files changed, 114 insertions, 63 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 34ecc27fc30a..3628a9fe705f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -393,13 +393,13 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, du->cursor_surface = vps->surf; du->cursor_dmabuf = vps->dmabuf; - /* setup new image */ if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; ret = vmw_cursor_update_image(dev_priv, vps->surf->snooper.image, - 64, 64, hotspot_x, hotspot_y); + 64, 64, hotspot_x, + hotspot_y); } else if (vps->dmabuf) { ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, plane->state->crtc_w, @@ -497,11 +497,22 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, struct vmw_surface *surface = NULL; struct drm_framebuffer *fb = new_state->fb; + struct drm_rect src = drm_plane_state_src(new_state); + struct drm_rect dest = drm_plane_state_dest(new_state); /* Turning off */ if (!fb) return ret; + ret = drm_plane_helper_check_update(plane, new_state->crtc, fb, + &src, &dest, + DRM_MODE_ROTATE_0, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true, &new_state->visible); + if (!ret) + return ret; + /* A lot of the code assumes this */ if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", @@ -566,13 +577,9 @@ void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, crtc->state->event = NULL; spin_lock_irq(&crtc->dev->event_lock); - if (drm_crtc_vblank_get(crtc) == 0) - drm_crtc_arm_vblank_event(crtc, event); - else - drm_crtc_send_vblank_event(crtc, event); + drm_crtc_send_vblank_event(crtc, event); spin_unlock_irq(&crtc->dev->event_lock); } - } @@ -675,9 +682,6 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) return NULL; vps->pinned = 0; - - /* Mapping is managed by prepare_fb/cleanup_fb */ - memset(&vps->host_map, 0, sizeof(vps->host_map)); vps->cpp = 0; /* Each ref counted resource needs to be acquired again */ @@ -739,11 +743,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, /* Should have been freed by cleanup_fb */ - if (vps->host_map.virtual) { - DRM_ERROR("Host mapping not freed\n"); - ttm_bo_kunmap(&vps->host_map); - } - if (vps->surf) vmw_surface_unreference(&vps->surf); @@ -888,11 +887,11 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, if (dev_priv->active_display_unit == vmw_du_screen_object) ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, clips, NULL, NULL, 0, 0, - num_clips, inc, NULL); + num_clips, inc, NULL, NULL); else ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, clips, NULL, NULL, 0, 0, - num_clips, inc, NULL); + num_clips, inc, NULL, NULL); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -928,11 +927,12 @@ int vmw_kms_readback(struct vmw_private *dev_priv, switch (dev_priv->active_display_unit) { case vmw_du_screen_object: return vmw_kms_sou_readback(dev_priv, file_priv, vfb, - user_fence_rep, vclips, num_clips); + user_fence_rep, vclips, num_clips, + NULL); case vmw_du_screen_target: return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, user_fence_rep, NULL, vclips, num_clips, - 1, false, true); + 1, false, true, NULL); default: WARN_ONCE(true, "Readback called with invalid display system.\n"); @@ -1090,12 +1090,12 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, case vmw_du_screen_target: ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, clips, NULL, num_clips, increment, - true, true); + true, true, NULL); break; case vmw_du_screen_object: ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, clips, NULL, num_clips, - increment, true, NULL); + increment, true, NULL, NULL); break; case vmw_du_legacy: ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, @@ -1121,12 +1121,14 @@ static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { }; /** - * Pin the dmabuffer to the start of vram. + * Pin the dmabuffer in a location suitable for access by the + * display system. */ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); struct vmw_dma_buffer *buf; + struct ttm_placement *placement; int ret; buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : @@ -1143,12 +1145,24 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) break; case vmw_du_screen_object: case vmw_du_screen_target: - if (vfb->dmabuf) - return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, - false); + if (vfb->dmabuf) { + if (dev_priv->capabilities & SVGA_CAP_3D) { + /* + * Use surface DMA to get content to + * sreen target surface. + */ + placement = &vmw_vram_gmr_placement; + } else { + /* Use CPU blit. */ + placement = &vmw_sys_placement; + } + } else { + /* Use surface / image update */ + placement = &vmw_mob_placement; + } - return vmw_dmabuf_pin_in_placement(dev_priv, buf, - &vmw_mob_placement, false); + return vmw_dmabuf_pin_in_placement(dev_priv, buf, placement, + false); default: return -EINVAL; } @@ -1539,35 +1553,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, return drm_atomic_helper_check(dev, state); } - -/** - * vmw_kms_atomic_commit - Perform an atomic state commit - * - * @dev: DRM device - * @state: the driver state object - * @nonblock: Whether nonblocking behaviour is requested - * - * This is a simple wrapper around drm_atomic_helper_commit() for - * us to clear the nonblocking value. - * - * Nonblocking commits currently cause synchronization issues - * for vmwgfx. - * - * RETURNS - * Zero for success or negative error code on failure. - */ -int vmw_kms_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - return drm_atomic_helper_commit(dev, state, false); -} - - static const struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, .atomic_check = vmw_kms_atomic_check_modeset, - .atomic_commit = vmw_kms_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static int vmw_kms_generic_present(struct vmw_private *dev_priv, @@ -1581,7 +1570,7 @@ static int vmw_kms_generic_present(struct vmw_private *dev_priv, { return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, &surface->res, destX, destY, - num_clips, 1, NULL); + num_clips, 1, NULL, NULL); } @@ -1600,7 +1589,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, case vmw_du_screen_target: ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, &surface->res, destX, destY, - num_clips, 1, NULL); + num_clips, 1, NULL, NULL); break; case vmw_du_screen_object: ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, @@ -2328,10 +2317,16 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, dirty->dev_priv = dev_priv; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); + /* If crtc is passed, no need to iterate over other display units */ + if (dirty->crtc) { + units[num_units++] = vmw_crtc_to_du(dirty->crtc); + } else { + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, + head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } } for (k = 0; k < num_units; k++) { @@ -2430,14 +2425,21 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible, - bool validate_as_mob) + bool validate_as_mob, + bool for_cpu_blit) { + struct ttm_operation_ctx ctx = { + .interruptible = interruptible, + .no_wait_gpu = false}; struct ttm_buffer_object *bo = &buf->base; int ret; ttm_bo_reserve(bo, false, false, NULL); - ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, - validate_as_mob); + if (for_cpu_blit) + ret = ttm_bo_validate(bo, &vmw_nonfixed_placement, &ctx); + else + ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, + validate_as_mob); if (ret) ttm_bo_unreserve(bo); @@ -2549,7 +2551,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, if (res->backup) { ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, interruptible, - res->dev_priv->has_mob); + res->dev_priv->has_mob, + false); if (ret) goto out_unreserve; } @@ -2845,3 +2848,51 @@ int vmw_kms_set_config(struct drm_mode_set *set, return drm_atomic_helper_set_config(set, ctx); } + + +/** + * vmw_kms_suspend - Save modesetting state and turn modesetting off. + * + * @dev: Pointer to the drm device + * Return: 0 on success. Negative error code on failure. + */ +int vmw_kms_suspend(struct drm_device *dev) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + + dev_priv->suspend_state = drm_atomic_helper_suspend(dev); + if (IS_ERR(dev_priv->suspend_state)) { + int ret = PTR_ERR(dev_priv->suspend_state); + + DRM_ERROR("Failed kms suspend: %d\n", ret); + dev_priv->suspend_state = NULL; + + return ret; + } + + return 0; +} + + +/** + * vmw_kms_resume - Re-enable modesetting and restore state + * + * @dev: Pointer to the drm device + * Return: 0 on success. Negative error code on failure. + * + * State is resumed from a previous vmw_kms_suspend(). It's illegal + * to call this function without a previous vmw_kms_suspend(). + */ +int vmw_kms_resume(struct drm_device *dev) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + int ret; + + if (WARN_ON(!dev_priv->suspend_state)) + return 0; + + ret = drm_atomic_helper_resume(dev, dev_priv->suspend_state); + dev_priv->suspend_state = NULL; + + return ret; +} |