diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 593 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 150 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 360 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 562 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_validation.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_validation.h | 37 |
13 files changed, 1220 insertions, 644 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 61a84b958d67..f05a29ff586e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -49,6 +49,8 @@ #define VMWGFX_REPO "In Tree" +#define VMWGFX_VALIDATION_MEM_GRAN (16*PAGE_SIZE) + /** * Fully encoded drm commands. Might move to vmw_drm.h @@ -665,7 +667,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); - mutex_init(&dev_priv->requested_layout_mutex); mutex_init(&dev_priv->global_kms_state_mutex); ttm_lock_init(&dev_priv->reservation_sem); spin_lock_init(&dev_priv->resource_lock); @@ -801,11 +802,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) 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; @@ -816,7 +812,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (unlikely(dev_priv->mmio_virt == NULL)) { ret = -ENOMEM; DRM_ERROR("Failed mapping MMIO.\n"); - goto out_err3; + goto out_err0; } /* Need mmio memory to check for fifo pitchlock cap. */ @@ -828,8 +824,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_err4; } - dev_priv->tdev = ttm_object_device_init - (dev_priv->mem_global_ref.object, 12, &vmw_prime_dmabuf_ops); + dev_priv->tdev = ttm_object_device_init(&ttm_mem_glob, 12, + &vmw_prime_dmabuf_ops); if (unlikely(dev_priv->tdev == NULL)) { DRM_ERROR("Unable to initialize TTM object management.\n"); @@ -870,7 +866,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } ret = ttm_bo_device_init(&dev_priv->bdev, - dev_priv->bo_global_ref.ref.object, &vmw_bo_driver, dev->anon_inode->i_mapping, VMWGFX_FILE_PAGE_OFFSET, @@ -918,7 +913,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) spin_unlock(&dev_priv->cap_lock); } - + vmw_validation_mem_init_ttm(dev_priv, VMWGFX_VALIDATION_MEM_GRAN); ret = vmw_kms_init(dev_priv); if (unlikely(ret != 0)) goto out_no_kms; @@ -992,8 +987,6 @@ out_no_device: ttm_object_device_release(&dev_priv->tdev); out_err4: memunmap(dev_priv->mmio_virt); -out_err3: - vmw_ttm_global_release(dev_priv); out_err0: for (i = vmw_res_context; i < vmw_res_max; ++i) idr_destroy(&dev_priv->res_idr[i]); @@ -1045,7 +1038,6 @@ static void vmw_driver_unload(struct drm_device *dev) memunmap(dev_priv->mmio_virt); if (dev_priv->ctx.staged_bindings) vmw_binding_state_free(dev_priv->ctx.staged_bindings); - vmw_ttm_global_release(dev_priv); for (i = vmw_res_context; i < vmw_res_max; ++i) idr_destroy(&dev_priv->res_idr[i]); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 59f614225bcd..cd607ba9c2fe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -417,8 +417,6 @@ enum { struct vmw_private { struct ttm_bo_device bdev; - struct ttm_bo_global_ref bo_global_ref; - struct drm_global_reference mem_global_ref; struct vmw_fifo_state fifo; @@ -468,15 +466,6 @@ struct vmw_private { uint32_t num_displays; /* - * Currently requested_layout_mutex is used to protect the gui - * positionig state in display unit. With that use case currently this - * mutex is only taken during layout ioctl and atomic check_modeset. - * Other display unit state can be protected with this mutex but that - * needs careful consideration. - */ - struct mutex requested_layout_mutex; - - /* * Framebuffer info. */ @@ -486,8 +475,6 @@ struct vmw_private { struct vmw_overlay *overlay_priv; struct drm_property *hotplug_mode_update_property; struct drm_property *implicit_placement_property; - unsigned num_implicit; - struct vmw_framebuffer *implicit_fb; struct mutex global_kms_state_mutex; spinlock_t cursor_lock; struct drm_atomic_state *suspend_state; @@ -606,6 +593,9 @@ struct vmw_private { struct vmw_cmdbuf_man *cman; DECLARE_BITMAP(irqthread_pending, VMW_IRQTHREAD_MAX); + + /* Validation memory reservation */ + struct vmw_validation_mem vvm; }; static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) @@ -842,10 +832,10 @@ extern int vmw_fifo_flush(struct vmw_private *dev_priv, * 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); +extern void vmw_validation_mem_init_ttm(struct vmw_private *dev_priv, + size_t gran); /** * TTM buffer object driver - vmwgfx_ttm_buffer.c */ @@ -1363,7 +1353,7 @@ vmw_bo_reference(struct vmw_buffer_object *buf) static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv) { - return (struct ttm_mem_global *) dev_priv->mem_global_ref.object; + return &ttm_mem_glob; } static inline void vmw_fifo_resource_inc(struct vmw_private *dev_priv) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 5a6b70ba137a..f2d13a72c05d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1738,7 +1738,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, void *buf) { struct vmw_buffer_object *vmw_bo; - int ret; struct { uint32_t header; @@ -1748,7 +1747,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, return vmw_translate_guest_ptr(dev_priv, sw_context, &cmd->body.ptr, &vmw_bo); - return ret; } @@ -3837,6 +3835,8 @@ int vmw_execbuf_process(struct drm_file *file_priv, struct sync_file *sync_file = NULL; DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1); + vmw_validation_set_val_mem(&val_ctx, &dev_priv->vvm); + if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) { out_fence_fd = get_unused_fd_flags(O_CLOEXEC); if (out_fence_fd < 0) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index f87261545f2c..301260e23e52 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -906,13 +906,10 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) container_of(action, struct vmw_event_fence_action, action); struct drm_device *dev = eaction->dev; struct drm_pending_event *event = eaction->event; - struct drm_file *file_priv; - if (unlikely(event == NULL)) return; - file_priv = event->file_priv; spin_lock_irq(&dev->event_lock); if (likely(eaction->tv_sec != NULL)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index dca04d4246ea..b351fb5214d3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -30,6 +30,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_rect.h> +#include <drm/drm_damage_helper.h> /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) @@ -456,21 +457,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct vmw_connector_state *vcs; struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); vcs = vmw_connector_state_to_vcs(du->connector.state); - - /* Only one active implicit framebuffer at a time. */ - mutex_lock(&dev_priv->global_kms_state_mutex); - if (vcs->is_implicit && dev_priv->implicit_fb && - !(dev_priv->num_implicit == 1 && du->active_implicit) - && dev_priv->implicit_fb != vfb) { - DRM_ERROR("Multiple implicit framebuffers " - "not supported.\n"); - ret = -EINVAL; - } - mutex_unlock(&dev_priv->global_kms_state_mutex); } @@ -493,24 +481,24 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *new_state) { int ret = 0; + struct drm_crtc_state *crtc_state = NULL; 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); + if (new_state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(new_state->state, + new_state->crtc); - /* Turning off */ - if (!fb) + ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) 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; + /* Turning off */ + if (!fb) + return 0; /* A lot of the code assumes this */ if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { @@ -846,58 +834,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) kfree(vfbs); } -static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, - 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 drm_clip_rect norect; - int ret, inc = 1; - - /* Legacy Display Unit does not support 3D */ - if (dev_priv->active_display_unit == vmw_du_legacy) - return -EINVAL; - - drm_modeset_lock_all(dev_priv->dev); - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) { - drm_modeset_unlock_all(dev_priv->dev); - return ret; - } - - 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 */ - } - - 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, NULL); - else - ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, - clips, NULL, NULL, 0, 0, - num_clips, inc, NULL, NULL); - - vmw_fifo_flush(dev_priv, false); - ttm_read_unlock(&dev_priv->reservation_sem); - - drm_modeset_unlock_all(dev_priv->dev); - - return 0; -} - /** * vmw_kms_readback - Perform a readback from the screen system to * a buffer-object backed framebuffer. @@ -941,7 +877,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { .destroy = vmw_framebuffer_surface_destroy, - .dirty = vmw_framebuffer_surface_dirty, + .dirty = drm_atomic_helper_dirtyfb, }; static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, @@ -1084,16 +1020,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, } switch (dev_priv->active_display_unit) { - case vmw_du_screen_target: - ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, - clips, NULL, num_clips, increment, - true, true, NULL); - break; - case vmw_du_screen_object: - ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, - clips, NULL, num_clips, - increment, true, NULL, NULL); - break; case vmw_du_legacy: ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, clips, num_clips, increment); @@ -1112,9 +1038,25 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, return ret; } +static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, + struct drm_file *file_priv, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips) +{ + struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); + + if (dev_priv->active_display_unit == vmw_du_legacy) + return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, + color, clips, num_clips); + + return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color, + clips, num_clips); +} + static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { .destroy = vmw_framebuffer_bo_destroy, - .dirty = vmw_framebuffer_bo_dirty, + .dirty = vmw_framebuffer_bo_dirty_ext, }; /** @@ -1565,6 +1507,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, } /** + * vmw_crtc_state_and_lock - Return new or current crtc state with locked + * crtc mutex + * @state: The atomic state pointer containing the new atomic state + * @crtc: The crtc + * + * This function returns the new crtc state if it's part of the state update. + * Otherwise returns the current crtc state. It also makes sure that the + * crtc mutex is locked. + * + * Returns: A valid crtc state pointer or NULL. It may also return a + * pointer error, in particular -EDEADLK if locking needs to be rerun. + */ +static struct drm_crtc_state * +vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (crtc_state) { + lockdep_assert_held(&crtc->mutex.mutex.base); + } else { + int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); + + if (ret != 0 && ret != -EALREADY) + return ERR_PTR(ret); + + crtc_state = crtc->state; + } + + return crtc_state; +} + +/** + * vmw_kms_check_implicit - Verify that all implicit display units scan out + * from the same fb after the new state is committed. + * @dev: The drm_device. + * @state: The new state to be checked. + * + * Returns: + * Zero on success, + * -EINVAL on invalid state, + * -EDEADLK if modeset locking needs to be rerun. + */ +static int vmw_kms_check_implicit(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct drm_framebuffer *implicit_fb = NULL; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane_state *plane_state; + + drm_for_each_crtc(crtc, dev) { + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + + if (!du->is_implicit) + continue; + + crtc_state = vmw_crtc_state_and_lock(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state || !crtc_state->enable) + continue; + + /* + * Can't move primary planes across crtcs, so this is OK. + * It also means we don't need to take the plane mutex. + */ + plane_state = du->primary.state; + if (plane_state->crtc != crtc) + continue; + + if (!implicit_fb) + implicit_fb = plane_state->fb; + else if (implicit_fb != plane_state->fb) + return -EINVAL; + } + + return 0; +} + +/** * vmw_kms_check_topology - Validates topology in drm_atomic_state * @dev: DRM device * @state: the driver state object @@ -1575,7 +1599,6 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, static int vmw_kms_check_topology(struct drm_device *dev, struct drm_atomic_state *state) { - struct vmw_private *dev_priv = vmw_priv(dev); struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_rect *rects; struct drm_crtc *crtc; @@ -1587,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev, if (!rects) return -ENOMEM; - mutex_lock(&dev_priv->requested_layout_mutex); - drm_for_each_crtc(crtc, dev) { struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - struct drm_crtc_state *crtc_state = crtc->state; + struct drm_crtc_state *crtc_state; i = drm_crtc_index(crtc); - if (crtc_state && crtc_state->enable) { + crtc_state = vmw_crtc_state_and_lock(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto clean; + } + + if (!crtc_state) + continue; + + if (crtc_state->enable) { rects[i].x1 = du->gui_x; rects[i].y1 = du->gui_y; rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; + } else { + rects[i].x1 = 0; + rects[i].y1 = 0; + rects[i].x2 = 0; + rects[i].y2 = 0; } } @@ -1611,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev, struct drm_connector_state *conn_state; struct vmw_connector_state *vmw_conn_state; - if (!new_crtc_state->enable) { - rects[i].x1 = 0; - rects[i].y1 = 0; - rects[i].x2 = 0; - rects[i].y2 = 0; - continue; - } - if (!du->pref_active) { ret = -EINVAL; goto clean; @@ -1639,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev, vmw_conn_state = vmw_connector_state_to_vcs(conn_state); vmw_conn_state->gui_x = du->gui_x; vmw_conn_state->gui_y = du->gui_y; - - rects[i].x1 = du->gui_x; - rects[i].y1 = du->gui_y; - rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; - rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; } ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, rects); clean: - mutex_unlock(&dev_priv->requested_layout_mutex); kfree(rects); return ret; } @@ -1681,6 +1702,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, if (ret) return ret; + ret = vmw_kms_check_implicit(dev, state); + if (ret) + return ret; + if (!state->allow_modeset) return ret; @@ -2003,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, struct vmw_display_unit *du; struct drm_connector *con; struct drm_connector_list_iter conn_iter; + struct drm_modeset_acquire_ctx ctx; + struct drm_crtc *crtc; + int ret; + + /* Currently gui_x/y is protected with the crtc mutex */ + mutex_lock(&dev->mode_config.mutex); + drm_modeset_acquire_init(&ctx, 0); +retry: + drm_for_each_crtc(crtc, dev) { + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret < 0) { + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + goto out_fini; + } + } - /* - * Currently only gui_x/y is protected with requested_layout_mutex. - */ - mutex_lock(&dev_priv->requested_layout_mutex); drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(con, &conn_iter) { du = vmw_connector_to_du(con); @@ -2026,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, } } drm_connector_list_iter_end(&conn_iter); - mutex_unlock(&dev_priv->requested_layout_mutex); - mutex_lock(&dev->mode_config.mutex); list_for_each_entry(con, &dev->mode_config.connector_list, head) { du = vmw_connector_to_du(con); if (num_rects > du->unit) { @@ -2048,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, } con->status = vmw_du_connector_detect(con, true); } - mutex_unlock(&dev->mode_config.mutex); drm_sysfs_hotplug_event(dev); - +out_fini: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + mutex_unlock(&dev->mode_config.mutex); + return 0; } @@ -2275,84 +2315,6 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, return 1; } -int vmw_du_connector_set_property(struct drm_connector *connector, - struct drm_property *property, - uint64_t val) -{ - struct vmw_display_unit *du = vmw_connector_to_du(connector); - struct vmw_private *dev_priv = vmw_priv(connector->dev); - - if (property == dev_priv->implicit_placement_property) - du->is_implicit = val; - - return 0; -} - - - -/** - * vmw_du_connector_atomic_set_property - Atomic version of get property - * - * @crtc - crtc the property is associated with - * - * Returns: - * Zero on success, negative errno on failure. - */ -int -vmw_du_connector_atomic_set_property(struct drm_connector *connector, - struct drm_connector_state *state, - struct drm_property *property, - uint64_t val) -{ - struct vmw_private *dev_priv = vmw_priv(connector->dev); - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); - struct vmw_display_unit *du = vmw_connector_to_du(connector); - - - if (property == dev_priv->implicit_placement_property) { - vcs->is_implicit = val; - - /* - * We should really be doing a drm_atomic_commit() to - * commit the new state, but since this doesn't cause - * an immedate state change, this is probably ok - */ - du->is_implicit = vcs->is_implicit; - } else { - return -EINVAL; - } - - return 0; -} - - -/** - * vmw_du_connector_atomic_get_property - Atomic version of get property - * - * @connector - connector the property is associated with - * - * Returns: - * Zero on success, negative errno on failure. - */ -int -vmw_du_connector_atomic_get_property(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, - uint64_t *val) -{ - struct vmw_private *dev_priv = vmw_priv(connector->dev); - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); - - if (property == dev_priv->implicit_placement_property) - *val = vcs->is_implicit; - else { - DRM_ERROR("Invalid Property %s\n", property->name); - return -EINVAL; - } - - return 0; -} - /** * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl * @dev: drm device for the ioctl @@ -2742,143 +2704,25 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, } /** - * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer - * - * @dev_priv: Pointer to a device private struct. - * @du: The display unit of the crtc. - */ -void vmw_kms_del_active(struct vmw_private *dev_priv, - struct vmw_display_unit *du) -{ - mutex_lock(&dev_priv->global_kms_state_mutex); - if (du->active_implicit) { - if (--(dev_priv->num_implicit) == 0) - dev_priv->implicit_fb = NULL; - du->active_implicit = false; - } - mutex_unlock(&dev_priv->global_kms_state_mutex); -} - -/** - * vmw_kms_add_active - register a crtc binding to an implicit framebuffer - * - * @vmw_priv: Pointer to a device private struct. - * @du: The display unit of the crtc. - * @vfb: The implicit framebuffer - * - * Registers a binding to an implicit framebuffer. - */ -void vmw_kms_add_active(struct vmw_private *dev_priv, - struct vmw_display_unit *du, - struct vmw_framebuffer *vfb) -{ - mutex_lock(&dev_priv->global_kms_state_mutex); - WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); - - if (!du->active_implicit && du->is_implicit) { - dev_priv->implicit_fb = vfb; - du->active_implicit = true; - dev_priv->num_implicit++; - } - mutex_unlock(&dev_priv->global_kms_state_mutex); -} - -/** - * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc. - * - * @dev_priv: Pointer to device-private struct. - * @crtc: The crtc we want to flip. - * - * Returns true or false depending whether it's OK to flip this crtc - * based on the criterion that we must not have more than one implicit - * frame-buffer at any one time. - */ -bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, - struct drm_crtc *crtc) -{ - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - bool ret; - - mutex_lock(&dev_priv->global_kms_state_mutex); - ret = !du->is_implicit || dev_priv->num_implicit == 1; - mutex_unlock(&dev_priv->global_kms_state_mutex); - - return ret; -} - -/** - * vmw_kms_update_implicit_fb - Update the implicit fb. - * - * @dev_priv: Pointer to device-private struct. - * @crtc: The crtc the new implicit frame-buffer is bound to. - */ -void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc) -{ - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - struct drm_plane *plane = crtc->primary; - struct vmw_framebuffer *vfb; - - mutex_lock(&dev_priv->global_kms_state_mutex); - - if (!du->is_implicit) - goto out_unlock; - - vfb = vmw_framebuffer_to_vfb(plane->state->fb); - WARN_ON_ONCE(dev_priv->num_implicit != 1 && - dev_priv->implicit_fb != vfb); - - dev_priv->implicit_fb = vfb; -out_unlock: - mutex_unlock(&dev_priv->global_kms_state_mutex); -} - -/** * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement * property. * * @dev_priv: Pointer to a device private struct. - * @immutable: Whether the property is immutable. * * Sets up the implicit placement property unless it's already set up. */ void -vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, - bool immutable) +vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv) { if (dev_priv->implicit_placement_property) return; dev_priv->implicit_placement_property = drm_property_create_range(dev_priv->dev, - immutable ? - DRM_MODE_PROP_IMMUTABLE : 0, + DRM_MODE_PROP_IMMUTABLE, "implicit_placement", 0, 1); - } - -/** - * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config - * - * @set: The configuration to set. - * - * The vmwgfx Xorg driver doesn't assign the mode::type member, which - * when drm_mode_set_crtcinfo is called as part of the configuration setting - * causes it to return incorrect crtc dimensions causing severe problems in - * the vmwgfx modesetting. So explicitly clear that member before calling - * into drm_atomic_helper_set_config. - */ -int vmw_kms_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx) -{ - if (set && set->mode) - set->mode->type = 0; - - return drm_atomic_helper_set_config(set, ctx); -} - - /** * vmw_kms_suspend - Save modesetting state and turn modesetting off. * @@ -2935,3 +2779,124 @@ void vmw_kms_lost_device(struct drm_device *dev) { drm_atomic_helper_shutdown(dev); } + +/** + * vmw_du_helper_plane_update - Helper to do plane update on a display unit. + * @update: The closure structure. + * + * Call this helper after setting callbacks in &vmw_du_update_plane to do plane + * update on display unit. + * + * Return: 0 on success or a negative error code on failure. + */ +int vmw_du_helper_plane_update(struct vmw_du_update_plane *update) +{ + struct drm_plane_state *state = update->plane->state; + struct drm_plane_state *old_state = update->old_state; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + struct drm_rect bb; + DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); + uint32_t reserved_size = 0; + uint32_t submit_size = 0; + uint32_t curr_size = 0; + uint32_t num_hits = 0; + void *cmd_start; + char *cmd_next; + int ret; + + /* + * Iterate in advance to check if really need plane update and find the + * number of clips that actually are in plane src for fifo allocation. + */ + drm_atomic_helper_damage_iter_init(&iter, old_state, state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + if (num_hits == 0) + return 0; + + if (update->vfb->bo) { + struct vmw_framebuffer_bo *vfbbo = + container_of(update->vfb, typeof(*vfbbo), base); + + ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false, + update->cpu_blit); + } else { + struct vmw_framebuffer_surface *vfbs = + container_of(update->vfb, typeof(*vfbs), base); + + ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res, + 0, NULL, NULL); + } + + if (ret) + return ret; + + ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr); + if (ret) + goto out_unref; + + reserved_size = update->calc_fifo_size(update, num_hits); + cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size); + if (!cmd_start) { + ret = -ENOMEM; + goto out_revert; + } + + cmd_next = cmd_start; + + if (update->post_prepare) { + curr_size = update->post_prepare(update, cmd_next); + cmd_next += curr_size; + submit_size += curr_size; + } + + if (update->pre_clip) { + curr_size = update->pre_clip(update, cmd_next, num_hits); + cmd_next += curr_size; + submit_size += curr_size; + } + + bb.x1 = INT_MAX; + bb.y1 = INT_MAX; + bb.x2 = INT_MIN; + bb.y2 = INT_MIN; + + drm_atomic_helper_damage_iter_init(&iter, old_state, state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + uint32_t fb_x = clip.x1; + uint32_t fb_y = clip.y1; + + vmw_du_translate_to_crtc(state, &clip); + if (update->clip) { + curr_size = update->clip(update, cmd_next, &clip, fb_x, + fb_y); + cmd_next += curr_size; + submit_size += curr_size; + } + bb.x1 = min_t(int, bb.x1, clip.x1); + bb.y1 = min_t(int, bb.y1, clip.y1); + bb.x2 = max_t(int, bb.x2, clip.x2); + bb.y2 = max_t(int, bb.y2, clip.y2); + } + + curr_size = update->post_clip(update, cmd_next, &bb); + submit_size += curr_size; + + if (reserved_size < submit_size) + submit_size = 0; + + vmw_fifo_commit(update->dev_priv, submit_size); + + vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx, + update->out_fence, NULL); + return ret; + +out_revert: + vmw_validation_revert(&val_ctx); + +out_unref: + vmw_validation_unref_lists(&val_ctx); + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 76ec570c0684..655abbcd4058 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -33,7 +33,123 @@ #include <drm/drm_encoder.h> #include "vmwgfx_drv.h" +/** + * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update + * @plane: Plane which is being updated. + * @old_state: Old state of plane. + * @dev_priv: Device private. + * @du: Display unit on which to update the plane. + * @vfb: Framebuffer which is blitted to display unit. + * @out_fence: Out fence for resource finish. + * @mutex: The mutex used to protect resource reservation. + * @cpu_blit: True if need cpu blit. + * @intr: Whether to perform waits interruptible if possible. + * + * This structure loosely represent the set of operations needed to perform a + * plane update on a display unit. Implementer will define that functionality + * according to the function callbacks for this structure. In brief it involves + * surface/buffer object validation, populate FIFO commands and command + * submission to the device. + */ +struct vmw_du_update_plane { + /** + * @calc_fifo_size: Calculate fifo size. + * + * Determine fifo size for the commands needed for update. The number of + * damage clips on display unit @num_hits will be passed to allocate + * sufficient fifo space. + * + * Return: Fifo size needed + */ + uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update, + uint32_t num_hits); + + /** + * @post_prepare: Populate fifo for resource preparation. + * + * Some surface resource or buffer object need some extra cmd submission + * like update GB image for proxy surface and define a GMRFB for screen + * object. That should should be done here as this callback will be + * called after FIFO allocation with the address of command buufer. + * + * This callback is optional. + * + * Return: Size of commands populated to command buffer. + */ + uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd); + + /** + * @pre_clip: Populate fifo before clip. + * + * This is where pre clip related command should be populated like + * surface copy/DMA, etc. + * + * This callback is optional. + * + * Return: Size of commands populated to command buffer. + */ + uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd, + uint32_t num_hits); + + /** + * @clip: Populate fifo for clip. + * + * This is where to populate clips for surface copy/dma or blit commands + * if needed. This will be called times have damage in display unit, + * which is one if doing full update. @clip is the damage in destination + * coordinates which is crtc/DU and @src_x, @src_y is damage clip src in + * framebuffer coordinate. + * + * This callback is optional. + * + * Return: Size of commands populated to command buffer. + */ + uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd, + struct drm_rect *clip, uint32_t src_x, uint32_t src_y); + + /** + * @post_clip: Populate fifo after clip. + * + * This is where to populate display unit update commands or blit + * commands. + * + * Return: Size of commands populated to command buffer. + */ + uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd, + struct drm_rect *bb); + + struct drm_plane *plane; + struct drm_plane_state *old_state; + struct vmw_private *dev_priv; + struct vmw_display_unit *du; + struct vmw_framebuffer *vfb; + struct vmw_fence_obj **out_fence; + struct mutex *mutex; + bool cpu_blit; + bool intr; +}; + +/** + * struct vmw_du_update_plane_surface - closure structure for surface + * @base: base closure structure. + * @cmd_start: FIFO command start address (used by SOU only). + */ +struct vmw_du_update_plane_surface { + struct vmw_du_update_plane base; + /* This member is to handle special case SOU surface update */ + void *cmd_start; +}; +/** + * struct vmw_du_update_plane_buffer - Closure structure for buffer object + * @base: Base closure structure. + * @fb_left: x1 for fb damage bounding box. + * @fb_top: y1 for fb damage bounding box. + */ +struct vmw_du_update_plane_buffer { + struct vmw_du_update_plane base; + int fb_left, fb_top; +}; /** * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty @@ -191,8 +307,6 @@ struct vmw_plane_state { struct vmw_connector_state { struct drm_connector_state base; - bool is_implicit; - /** * @gui_x: * @@ -254,7 +368,6 @@ struct vmw_display_unit { int gui_x; int gui_y; bool is_implicit; - bool active_implicit; int set_gui_x; int set_gui_y; }; @@ -334,17 +447,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, struct drm_crtc **p_crtc, struct drm_display_mode **p_mode); void vmw_guess_mode_timing(struct drm_display_mode *mode); -void vmw_kms_del_active(struct vmw_private *dev_priv, - struct vmw_display_unit *du); -void vmw_kms_add_active(struct vmw_private *dev_priv, - struct vmw_display_unit *du, - struct vmw_framebuffer *vfb); -bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, - struct drm_crtc *crtc); -void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc); -void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, - bool immutable); +void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); +void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); /* Universal Plane Helpers */ void vmw_du_primary_plane_destroy(struct drm_plane *plane); @@ -456,6 +560,20 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, bool interruptible, struct drm_crtc *crtc); -int vmw_kms_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx); +int vmw_du_helper_plane_update(struct vmw_du_update_plane *update); + +/** + * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc + * @state: Plane state. + * @r: Rectangle to translate. + */ +static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state, + struct drm_rect *r) +{ + int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x); + int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y); + + drm_rect_translate(r, translate_crtc_x, translate_crtc_y); +} + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 723578117191..16be515c4c0f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -233,7 +233,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { .reset = vmw_du_crtc_reset, .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, - .set_config = vmw_kms_set_config, + .set_config = drm_atomic_helper_set_config, }; @@ -263,18 +263,14 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = { .dpms = vmw_du_connector_dpms, .detect = vmw_du_connector_detect, .fill_modes = vmw_du_connector_fill_modes, - .set_property = vmw_du_connector_set_property, .destroy = vmw_ldu_connector_destroy, .reset = vmw_du_connector_reset, .atomic_duplicate_state = vmw_du_connector_duplicate_state, .atomic_destroy_state = vmw_du_connector_destroy_state, - .atomic_set_property = vmw_du_connector_atomic_set_property, - .atomic_get_property = vmw_du_connector_atomic_get_property, }; static const struct drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; /* @@ -417,7 +413,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); - vmw_du_connector_reset(connector); ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -428,8 +423,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); connector->status = vmw_du_connector_detect(connector, true); - vmw_connector_state_to_vcs(connector->state)->is_implicit = true; - ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); @@ -448,7 +441,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_encoder; } - vmw_du_crtc_reset(crtc); ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, &ldu->base.cursor, @@ -514,7 +506,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) if (ret != 0) goto err_free; - vmw_kms_create_implicit_placement_property(dev_priv, true); + vmw_kms_create_implicit_placement_property(dev_priv); if (dev_priv->capabilities & SVGA_CAP_MULTIMON) for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 8a029bade32a..3025bfc001a1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -85,7 +85,7 @@ static void vmw_resource_release(struct kref *kref) struct ttm_validate_buffer val_buf; val_buf.bo = bo; - val_buf.shared = false; + val_buf.num_shared = 0; res->func->unbind(res, false, &val_buf); } res->backup_dirty = false; @@ -462,7 +462,7 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket, INIT_LIST_HEAD(&val_list); val_buf->bo = ttm_bo_reference(&res->backup->base); - val_buf->shared = false; + val_buf->num_shared = 0; list_add_tail(&val_buf->head, &val_list); ret = ttm_eu_reserve_buffers(ticket, &val_list, interruptible, NULL); if (unlikely(ret != 0)) @@ -565,7 +565,7 @@ static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket, BUG_ON(!func->may_evict); val_buf.bo = NULL; - val_buf.shared = false; + val_buf.num_shared = 0; ret = vmw_resource_check_buffer(ticket, res, interruptible, &val_buf); if (unlikely(ret != 0)) return ret; @@ -614,7 +614,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr) return 0; val_buf.bo = NULL; - val_buf.shared = false; + val_buf.num_shared = 0; if (res->backup) val_buf.bo = &res->backup->base; do { @@ -685,7 +685,7 @@ void vmw_resource_unbind_list(struct vmw_buffer_object *vbo) struct vmw_resource *res, *next; struct ttm_validate_buffer val_buf = { .bo = &vbo->base, - .shared = false + .num_shared = 0 }; lockdep_assert_held(&vbo->base.resv->lock.base); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 53316b1bda3d..cd586c52af7e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -29,6 +29,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_damage_helper.h> #define vmw_crtc_to_sou(x) \ @@ -76,6 +77,11 @@ struct vmw_kms_sou_dirty_cmd { SVGA3dCmdBlitSurfaceToScreen body; }; +struct vmw_kms_sou_define_gmrfb { + uint32_t header; + SVGAFifoCmdDefineGMRFB body; +}; + /** * Display unit using screen objects. */ @@ -241,28 +247,20 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) sou->buffer = vps->bo; sou->buffer_size = vps->bo_size; - if (sou->base.is_implicit) { - x = crtc->x; - y = crtc->y; - } else { - conn_state = sou->base.connector.state; - vmw_conn_state = vmw_connector_state_to_vcs(conn_state); + conn_state = sou->base.connector.state; + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); - x = vmw_conn_state->gui_x; - y = vmw_conn_state->gui_y; - } + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); if (ret) DRM_ERROR("Failed to define Screen Object %dx%d\n", crtc->x, crtc->y); - vmw_kms_add_active(dev_priv, &sou->base, vfb); } else { sou->buffer = NULL; sou->buffer_size = 0; - - vmw_kms_del_active(dev_priv, &sou->base); } } @@ -317,38 +315,14 @@ static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc, } } -static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *new_fb, - struct drm_pending_vblank_event *event, - uint32_t flags, - struct drm_modeset_acquire_ctx *ctx) -{ - struct vmw_private *dev_priv = vmw_priv(crtc->dev); - int ret; - - if (!vmw_kms_crtc_flippable(dev_priv, crtc)) - return -EINVAL; - - ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); - if (ret) { - DRM_ERROR("Page flip error %d.\n", ret); - return ret; - } - - if (vmw_crtc_to_du(crtc)->is_implicit) - vmw_kms_update_implicit_fb(dev_priv, crtc); - - return ret; -} - static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_sou_crtc_destroy, .reset = vmw_du_crtc_reset, .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, - .set_config = vmw_kms_set_config, - .page_flip = vmw_sou_crtc_page_flip, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, }; /* @@ -377,19 +351,15 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = { .dpms = vmw_du_connector_dpms, .detect = vmw_du_connector_detect, .fill_modes = vmw_du_connector_fill_modes, - .set_property = vmw_du_connector_set_property, .destroy = vmw_sou_connector_destroy, .reset = vmw_du_connector_reset, .atomic_duplicate_state = vmw_du_connector_duplicate_state, .atomic_destroy_state = vmw_du_connector_destroy_state, - .atomic_set_property = vmw_du_connector_atomic_set_property, - .atomic_get_property = vmw_du_connector_atomic_get_property, }; static const struct drm_connector_helper_funcs vmw_sou_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; @@ -499,6 +469,263 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); } +static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + return sizeof(struct vmw_kms_sou_define_gmrfb) + + sizeof(struct vmw_kms_sou_bo_blit) * num_hits; +} + +static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update, + void *cmd) +{ + struct vmw_framebuffer_bo *vfbbo = + container_of(update->vfb, typeof(*vfbbo), base); + struct vmw_kms_sou_define_gmrfb *gmr = cmd; + int depth = update->vfb->base.format->depth; + + /* Emulate RGBA support, contrary to svga_reg.h this is not + * supported by hosts. This is only a problem if we are reading + * this value later and expecting what we uploaded back. + */ + if (depth == 32) + depth = 24; + + gmr->header = SVGA_CMD_DEFINE_GMRFB; + + gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8; + gmr->body.format.colorDepth = depth; + gmr->body.format.reserved = 0; + gmr->body.bytesPerLine = update->vfb->base.pitches[0]; + vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr); + + return sizeof(*gmr); +} + +static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *clip, + uint32_t fb_x, uint32_t fb_y) +{ + struct vmw_kms_sou_bo_blit *blit = cmd; + + blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; + blit->body.destScreenId = update->du->unit; + blit->body.srcOrigin.x = fb_x; + blit->body.srcOrigin.y = fb_y; + blit->body.destRect.left = clip->x1; + blit->body.destRect.top = clip->y1; + blit->body.destRect.right = clip->x2; + blit->body.destRect.bottom = clip->y2; + + return sizeof(*blit); +} + +static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *bb) +{ + return 0; +} + +/** + * vmw_sou_plane_update_bo - Update display unit for bo backed fb. + * @dev_priv: Device private. + * @plane: Plane state. + * @old_state: Old plane state. + * @vfb: Framebuffer which is blitted to display unit. + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. + * The returned fence pointer may be NULL in which case the device + * has already synchronized. + * + * Return: 0 on success or a negative error code on failure. + */ +static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv, + struct drm_plane *plane, + struct drm_plane_state *old_state, + struct vmw_framebuffer *vfb, + struct vmw_fence_obj **out_fence) +{ + struct vmw_du_update_plane_buffer bo_update; + + memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); + bo_update.base.plane = plane; + bo_update.base.old_state = old_state; + bo_update.base.dev_priv = dev_priv; + bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); + bo_update.base.vfb = vfb; + bo_update.base.out_fence = out_fence; + bo_update.base.mutex = NULL; + bo_update.base.cpu_blit = false; + bo_update.base.intr = true; + + bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size; + bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb; + bo_update.base.clip = vmw_sou_bo_populate_clip; + bo_update.base.post_clip = vmw_stud_bo_post_clip; + + return vmw_du_helper_plane_update(&bo_update.base); +} + +static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * + num_hits; +} + +static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update, + void *cmd) +{ + struct vmw_du_update_plane_surface *srf_update; + + srf_update = container_of(update, typeof(*srf_update), base); + + /* + * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that + * its bounding box is filled before iterating over all the clips. So + * store the FIFO start address and revisit to fill the details. + */ + srf_update->cmd_start = cmd; + + return 0; +} + +static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update, + void *cmd, uint32_t num_hits) +{ + struct vmw_kms_sou_dirty_cmd *blit = cmd; + struct vmw_framebuffer_surface *vfbs; + + vfbs = container_of(update->vfb, typeof(*vfbs), base); + + blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; + blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * + num_hits; + + blit->body.srcImage.sid = vfbs->surface->res.id; + blit->body.destScreenId = update->du->unit; + + /* Update the source and destination bounding box later in post_clip */ + blit->body.srcRect.left = 0; + blit->body.srcRect.top = 0; + blit->body.srcRect.right = 0; + blit->body.srcRect.bottom = 0; + + blit->body.destRect.left = 0; + blit->body.destRect.top = 0; + blit->body.destRect.right = 0; + blit->body.destRect.bottom = 0; + + return sizeof(*blit); +} + +static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *clip, + uint32_t src_x, uint32_t src_y) +{ + SVGASignedRect *rect = cmd; + + /* + * rects are relative to dest bounding box rect on screen object, so + * translate to it later in post_clip + */ + rect->left = clip->x1; + rect->top = clip->y1; + rect->right = clip->x2; + rect->bottom = clip->y2; + + return sizeof(*rect); +} + +static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *bb) +{ + struct vmw_du_update_plane_surface *srf_update; + struct drm_plane_state *state = update->plane->state; + struct drm_rect src_bb; + struct vmw_kms_sou_dirty_cmd *blit; + SVGASignedRect *rect; + uint32_t num_hits; + int translate_src_x; + int translate_src_y; + int i; + + srf_update = container_of(update, typeof(*srf_update), base); + + blit = srf_update->cmd_start; + rect = (SVGASignedRect *)&blit[1]; + + num_hits = (blit->header.size - sizeof(blit->body))/ + sizeof(SVGASignedRect); + + src_bb = *bb; + + /* To translate bb back to fb src coord */ + translate_src_x = (state->src_x >> 16) - state->crtc_x; + translate_src_y = (state->src_y >> 16) - state->crtc_y; + + drm_rect_translate(&src_bb, translate_src_x, translate_src_y); + + blit->body.srcRect.left = src_bb.x1; + blit->body.srcRect.top = src_bb.y1; + blit->body.srcRect.right = src_bb.x2; + blit->body.srcRect.bottom = src_bb.y2; + + blit->body.destRect.left = bb->x1; + blit->body.destRect.top = bb->y1; + blit->body.destRect.right = bb->x2; + blit->body.destRect.bottom = bb->y2; + + /* rects are relative to dest bb rect */ + for (i = 0; i < num_hits; i++) { + rect->left -= bb->x1; + rect->top -= bb->y1; + rect->right -= bb->x1; + rect->bottom -= bb->y1; + rect++; + } + + return 0; +} + +/** + * vmw_sou_plane_update_surface - Update display unit for surface backed fb. + * @dev_priv: Device private. + * @plane: Plane state. + * @old_state: Old plane state. + * @vfb: Framebuffer which is blitted to display unit + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. + * The returned fence pointer may be NULL in which case the device + * has already synchronized. + * + * Return: 0 on success or a negative error code on failure. + */ +static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv, + struct drm_plane *plane, + struct drm_plane_state *old_state, + struct vmw_framebuffer *vfb, + struct vmw_fence_obj **out_fence) +{ + struct vmw_du_update_plane_surface srf_update; + + memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface)); + srf_update.base.plane = plane; + srf_update.base.old_state = old_state; + srf_update.base.dev_priv = dev_priv; + srf_update.base.du = vmw_crtc_to_du(plane->state->crtc); + srf_update.base.vfb = vfb; + srf_update.base.out_fence = out_fence; + srf_update.base.mutex = &dev_priv->cmdbuf_mutex; + srf_update.base.cpu_blit = false; + srf_update.base.intr = true; + + srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size; + srf_update.base.post_prepare = vmw_sou_surface_post_prepare; + srf_update.base.pre_clip = vmw_sou_surface_pre_clip; + srf_update.base.clip = vmw_sou_surface_clip_rect; + srf_update.base.post_clip = vmw_sou_surface_post_clip; + + return vmw_du_helper_plane_update(&srf_update.base); +} static void vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, @@ -509,47 +736,28 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, struct vmw_fence_obj *fence = NULL; int ret; + /* In case of device error, maintain consistent atomic state */ if (crtc && plane->state->fb) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(plane->state->fb); - struct drm_vmw_rect vclips; - - vclips.x = crtc->x; - vclips.y = crtc->y; - vclips.w = crtc->mode.hdisplay; - vclips.h = crtc->mode.vdisplay; if (vfb->bo) - ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, - &vclips, 1, 1, true, - &fence, crtc); + ret = vmw_sou_plane_update_bo(dev_priv, plane, + old_state, vfb, &fence); else - ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, - &vclips, NULL, 0, 0, - 1, 1, &fence, crtc); - - /* - * We cannot really fail this function, so if we do, then output - * an error and maintain consistent atomic state. - */ + ret = vmw_sou_plane_update_surface(dev_priv, plane, + old_state, vfb, + &fence); if (ret != 0) DRM_ERROR("Failed to update screen.\n"); } else { - /* - * When disabling a plane, CRTC and FB should always be NULL - * together, otherwise it's an error. - * Here primary plane is being disable so should really blank - * the screen object display unit, if not already done. - */ + /* Do nothing when fb and crtc is NULL (blank crtc) */ return; } + /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ event = crtc->state->event; - /* - * In case of failure and other cases, vblank event will be sent in - * vmw_du_crtc_atomic_flush. - */ if (event && fence) { struct drm_file *file_priv = event->base.file_priv; @@ -640,7 +848,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) primary = &sou->base.primary; cursor = &sou->base.cursor; - sou->base.active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = dev_priv->initial_width; sou->base.pref_height = dev_priv->initial_height; @@ -666,6 +873,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) } drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary); /* Initialize cursor plane */ vmw_du_plane_reset(cursor); @@ -693,8 +901,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); connector->status = vmw_du_connector_detect(connector, true); - vmw_connector_state_to_vcs(connector->state)->is_implicit = false; - ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); @@ -733,12 +939,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.suggested_y_property, 0); - if (dev_priv->implicit_placement_property) - drm_object_attach_property - (&connector->base, - dev_priv->implicit_placement_property, - sou->base.is_implicit); - return 0; err_free_unregister: @@ -764,15 +964,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) } ret = -ENOMEM; - dev_priv->num_implicit = 0; - dev_priv->implicit_fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); if (unlikely(ret != 0)) return ret; - vmw_kms_create_implicit_placement_property(dev_priv, false); - for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) vmw_sou_init(dev_priv, i); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index e086565c1da6..096c2941a8e4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -30,7 +30,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> - +#include <drm/drm_damage_helper.h> #define vmw_crtc_to_stdu(x) \ container_of(x, struct vmw_screen_target_display_unit, base.crtc) @@ -92,6 +92,10 @@ struct vmw_stdu_surface_copy { SVGA3dCmdSurfaceCopy body; }; +struct vmw_stdu_update_gb_image { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBImage body; +}; /** * struct vmw_screen_target_display_unit @@ -396,13 +400,8 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) if (!crtc->state->enable) return; - if (stdu->base.is_implicit) { - x = crtc->x; - y = crtc->y; - } else { - x = vmw_conn_state->gui_x; - y = vmw_conn_state->gui_y; - } + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; vmw_svga_enable(dev_priv); ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); @@ -417,27 +416,9 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) { } - static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct drm_plane_state *plane_state = crtc->primary->state; - struct vmw_private *dev_priv; - struct vmw_screen_target_display_unit *stdu; - struct vmw_framebuffer *vfb; - struct drm_framebuffer *fb; - - - stdu = vmw_crtc_to_stdu(crtc); - dev_priv = vmw_priv(crtc->dev); - fb = plane_state->fb; - - vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; - - if (vfb) - vmw_kms_add_active(dev_priv, &stdu->base, vfb); - else - vmw_kms_del_active(dev_priv, &stdu->base); } static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, @@ -472,49 +453,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, } /** - * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target - * - * @crtc: CRTC to attach FB to - * @fb: FB to attach - * @event: Event to be posted. This event should've been alloced - * using k[mz]alloc, and should've been completely initialized. - * @page_flip_flags: Input flags. - * - * If the STDU uses the same display and content buffers, i.e. a true flip, - * this function will replace the existing display buffer with the new content - * buffer. - * - * If the STDU uses different display and content buffers, i.e. a blit, then - * only the content buffer will be updated. - * - * RETURNS: - * 0 on success, error code on failure - */ -static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *new_fb, - struct drm_pending_vblank_event *event, - uint32_t flags, - struct drm_modeset_acquire_ctx *ctx) - -{ - struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); - int ret; - - if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) - return -EINVAL; - - ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); - if (ret) { - DRM_ERROR("Page flip error %d.\n", ret); - return ret; - } - - return 0; -} - - -/** * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect * * @dirty: The closure structure. @@ -986,8 +924,8 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { .reset = vmw_du_crtc_reset, .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, - .set_config = vmw_kms_set_config, - .page_flip = vmw_stdu_crtc_page_flip, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, }; @@ -1042,19 +980,15 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = { .dpms = vmw_du_connector_dpms, .detect = vmw_du_connector_detect, .fill_modes = vmw_du_connector_fill_modes, - .set_property = vmw_du_connector_set_property, .destroy = vmw_stdu_connector_destroy, .reset = vmw_du_connector_reset, .atomic_duplicate_state = vmw_du_connector_duplicate_state, .atomic_destroy_state = vmw_du_connector_destroy_state, - .atomic_set_property = vmw_du_connector_atomic_set_property, - .atomic_get_property = vmw_du_connector_atomic_get_property, }; static const struct drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; @@ -1257,11 +1191,402 @@ out_srf_unref: return ret; } +static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits + + sizeof(SVGA3dCmdSurfaceDMASuffix) + + sizeof(struct vmw_stdu_update); +} + +static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + return sizeof(struct vmw_stdu_update_gb_image) + + sizeof(struct vmw_stdu_update); +} + +static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update, + void *cmd, uint32_t num_hits) +{ + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer_bo *vfbbo; + struct vmw_stdu_dma *cmd_dma = cmd; + + stdu = container_of(update->du, typeof(*stdu), base); + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); + + cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA; + cmd_dma->header.size = sizeof(cmd_dma->body) + + sizeof(struct SVGA3dCopyBox) * num_hits + + sizeof(SVGA3dCmdSurfaceDMASuffix); + vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr); + cmd_dma->body.guest.pitch = update->vfb->base.pitches[0]; + cmd_dma->body.host.sid = stdu->display_srf->res.id; + cmd_dma->body.host.face = 0; + cmd_dma->body.host.mipmap = 0; + cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM; + + return sizeof(*cmd_dma); +} + +static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *clip, + uint32_t fb_x, uint32_t fb_y) +{ + struct SVGA3dCopyBox *box = cmd; + + box->srcx = fb_x; + box->srcy = fb_y; + box->srcz = 0; + box->x = clip->x1; + box->y = clip->y1; + box->z = 0; + box->w = drm_rect_width(clip); + box->h = drm_rect_height(clip); + box->d = 1; + + return sizeof(*box); +} + +static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *bb) +{ + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer_bo *vfbbo; + SVGA3dCmdSurfaceDMASuffix *suffix = cmd; + + stdu = container_of(update->du, typeof(*stdu), base); + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); + + suffix->suffixSize = sizeof(*suffix); + suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE; + + vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2, + bb->y1, bb->y2); + + return sizeof(*suffix) + sizeof(struct vmw_stdu_update); +} + +static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update, + void *cmd, uint32_t num_hits) +{ + struct vmw_du_update_plane_buffer *bo_update = + container_of(update, typeof(*bo_update), base); + + bo_update->fb_left = INT_MAX; + bo_update->fb_top = INT_MAX; + + return 0; +} + +static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update, + void *cmd, struct drm_rect *clip, + uint32_t fb_x, uint32_t fb_y) +{ + struct vmw_du_update_plane_buffer *bo_update = + container_of(update, typeof(*bo_update), base); + + bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x); + bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y); + + return 0; +} + +static uint32_t +vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, + struct drm_rect *bb) +{ + struct vmw_du_update_plane_buffer *bo_update; + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer_bo *vfbbo; + struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0); + struct vmw_stdu_update_gb_image *cmd_img = cmd; + struct vmw_stdu_update *cmd_update; + struct ttm_buffer_object *src_bo, *dst_bo; + u32 src_offset, dst_offset; + s32 src_pitch, dst_pitch; + s32 width, height; + + bo_update = container_of(update, typeof(*bo_update), base); + stdu = container_of(update->du, typeof(*stdu), base); + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); + + width = bb->x2 - bb->x1; + height = bb->y2 - bb->y1; + + diff.cpp = stdu->cpp; + + dst_bo = &stdu->display_srf->res.backup->base; + dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; + dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; + + src_bo = &vfbbo->buffer->base; + src_pitch = update->vfb->base.pitches[0]; + src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * + stdu->cpp; + + (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo, + src_offset, src_pitch, width * stdu->cpp, height, + &diff); + + if (drm_rect_visible(&diff.rect)) { + SVGA3dBox *box = &cmd_img->body.box; + + cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + cmd_img->header.size = sizeof(cmd_img->body); + cmd_img->body.image.sid = stdu->display_srf->res.id; + cmd_img->body.image.face = 0; + cmd_img->body.image.mipmap = 0; + + box->x = diff.rect.x1; + box->y = diff.rect.y1; + box->z = 0; + box->w = drm_rect_width(&diff.rect); + box->h = drm_rect_height(&diff.rect); + box->d = 1; + + cmd_update = (struct vmw_stdu_update *)&cmd_img[1]; + vmw_stdu_populate_update(cmd_update, stdu->base.unit, + diff.rect.x1, diff.rect.x2, + diff.rect.y1, diff.rect.y2); + + return sizeof(*cmd_img) + sizeof(*cmd_update); + } + + return 0; +} + +/** + * vmw_stdu_plane_update_bo - Update display unit for bo backed fb. + * @dev_priv: device private. + * @plane: plane state. + * @old_state: old plane state. + * @vfb: framebuffer which is blitted to display unit. + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. + * The returned fence pointer may be NULL in which case the device + * has already synchronized. + * + * Return: 0 on success or a negative error code on failure. + */ +static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, + struct drm_plane *plane, + struct drm_plane_state *old_state, + struct vmw_framebuffer *vfb, + struct vmw_fence_obj **out_fence) +{ + struct vmw_du_update_plane_buffer bo_update; + + memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); + bo_update.base.plane = plane; + bo_update.base.old_state = old_state; + bo_update.base.dev_priv = dev_priv; + bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); + bo_update.base.vfb = vfb; + bo_update.base.out_fence = out_fence; + bo_update.base.mutex = NULL; + bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); + bo_update.base.intr = false; + + /* + * VM without 3D support don't have surface DMA command and framebuffer + * should be moved out of VRAM. + */ + if (bo_update.base.cpu_blit) { + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu; + bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu; + bo_update.base.clip = vmw_stdu_bo_clip_cpu; + bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu; + } else { + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size; + bo_update.base.pre_clip = vmw_stdu_bo_populate_dma; + bo_update.base.clip = vmw_stdu_bo_populate_clip; + bo_update.base.post_clip = vmw_stdu_bo_populate_update; + } + + return vmw_du_helper_plane_update(&bo_update.base); +} + +static uint32_t +vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + struct vmw_framebuffer_surface *vfbs; + uint32_t size = 0; + + vfbs = container_of(update->vfb, typeof(*vfbs), base); + + if (vfbs->is_bo_proxy) + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; + + size += sizeof(struct vmw_stdu_update); + + return size; +} + +static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, + uint32_t num_hits) +{ + struct vmw_framebuffer_surface *vfbs; + uint32_t size = 0; + + vfbs = container_of(update->vfb, typeof(*vfbs), base); + + if (vfbs->is_bo_proxy) + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; + + size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * + num_hits + sizeof(struct vmw_stdu_update); + + return size; +} + +static uint32_t +vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) +{ + struct vmw_framebuffer_surface *vfbs; + struct drm_plane_state *state = update->plane->state; + struct drm_plane_state *old_state = update->old_state; + struct vmw_stdu_update_gb_image *cmd_update = cmd; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + uint32_t copy_size = 0; + + vfbs = container_of(update->vfb, typeof(*vfbs), base); + + /* + * proxy surface is special where a buffer object type fb is wrapped + * in a surface and need an update gb image command to sync with device. + */ + drm_atomic_helper_damage_iter_init(&iter, old_state, state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + SVGA3dBox *box = &cmd_update->body.box; + + cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + cmd_update->header.size = sizeof(cmd_update->body); + cmd_update->body.image.sid = vfbs->surface->res.id; + cmd_update->body.image.face = 0; + cmd_update->body.image.mipmap = 0; + + box->x = clip.x1; + box->y = clip.y1; + box->z = 0; + box->w = drm_rect_width(&clip); + box->h = drm_rect_height(&clip); + box->d = 1; + + copy_size += sizeof(*cmd_update); + cmd_update++; + } + + return copy_size; +} + +static uint32_t +vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, + uint32_t num_hits) +{ + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer_surface *vfbs; + struct vmw_stdu_surface_copy *cmd_copy = cmd; + + stdu = container_of(update->du, typeof(*stdu), base); + vfbs = container_of(update->vfb, typeof(*vfbs), base); + + cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; + cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * + num_hits; + cmd_copy->body.src.sid = vfbs->surface->res.id; + cmd_copy->body.dest.sid = stdu->display_srf->res.id; + + return sizeof(*cmd_copy); +} + +static uint32_t +vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd, + struct drm_rect *clip, uint32_t fb_x, + uint32_t fb_y) +{ + struct SVGA3dCopyBox *box = cmd; + + box->srcx = fb_x; + box->srcy = fb_y; + box->srcz = 0; + box->x = clip->x1; + box->y = clip->y1; + box->z = 0; + box->w = drm_rect_width(clip); + box->h = drm_rect_height(clip); + box->d = 1; + + return sizeof(*box); +} + +static uint32_t +vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd, + struct drm_rect *bb) +{ + vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1, + bb->y2); + return sizeof(struct vmw_stdu_update); +} /** - * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane + * vmw_stdu_plane_update_surface - Update display unit for surface backed fb + * @dev_priv: Device private + * @plane: Plane state + * @old_state: Old plane state + * @vfb: Framebuffer which is blitted to display unit + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. + * The returned fence pointer may be NULL in which case the device + * has already synchronized. * + * Return: 0 on success or a negative error code on failure. + */ +static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, + struct drm_plane *plane, + struct drm_plane_state *old_state, + struct vmw_framebuffer *vfb, + struct vmw_fence_obj **out_fence) +{ + struct vmw_du_update_plane srf_update; + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer_surface *vfbs; + + stdu = vmw_crtc_to_stdu(plane->state->crtc); + vfbs = container_of(vfb, typeof(*vfbs), base); + + memset(&srf_update, 0, sizeof(struct vmw_du_update_plane)); + srf_update.plane = plane; + srf_update.old_state = old_state; + srf_update.dev_priv = dev_priv; + srf_update.du = vmw_crtc_to_du(plane->state->crtc); + srf_update.vfb = vfb; + srf_update.out_fence = out_fence; + srf_update.mutex = &dev_priv->cmdbuf_mutex; + srf_update.cpu_blit = false; + srf_update.intr = true; + + if (vfbs->is_bo_proxy) + srf_update.post_prepare = vmw_stdu_surface_update_proxy; + + if (vfbs->surface->res.id != stdu->display_srf->res.id) { + srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; + srf_update.pre_clip = vmw_stdu_surface_populate_copy; + srf_update.clip = vmw_stdu_surface_populate_clip; + } else { + srf_update.calc_fifo_size = + vmw_stdu_surface_fifo_size_same_display; + } + + srf_update.post_clip = vmw_stdu_surface_populate_update; + + return vmw_du_helper_plane_update(&srf_update); +} + +/** + * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane * @plane: display plane * @old_state: Only used to get crtc info * @@ -1278,17 +1603,14 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, struct drm_crtc *crtc = plane->state->crtc; struct vmw_screen_target_display_unit *stdu; struct drm_pending_vblank_event *event; + struct vmw_fence_obj *fence = NULL; struct vmw_private *dev_priv; int ret; - /* - * We cannot really fail this function, so if we do, then output an - * error and maintain consistent atomic state. - */ + /* If case of device error, maintain consistent atomic state */ if (crtc && plane->state->fb) { struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(plane->state->fb); - struct drm_vmw_rect vclips; stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); @@ -1296,23 +1618,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, stdu->content_fb_type = vps->content_fb_type; stdu->cpp = vps->cpp; - vclips.x = crtc->x; - vclips.y = crtc->y; - vclips.w = crtc->mode.hdisplay; - vclips.h = crtc->mode.vdisplay; - ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); if (ret) DRM_ERROR("Failed to bind surface to STDU.\n"); if (vfb->bo) - ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, - &vclips, 1, 1, true, false, - crtc); + ret = vmw_stdu_plane_update_bo(dev_priv, plane, + old_state, vfb, &fence); else - ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, - &vclips, NULL, 0, 0, - 1, 1, NULL, crtc); + ret = vmw_stdu_plane_update_surface(dev_priv, plane, + old_state, vfb, + &fence); if (ret) DRM_ERROR("Failed to update STDU.\n"); } else { @@ -1320,12 +1636,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); - /* - * When disabling a plane, CRTC and FB should always be NULL - * together, otherwise it's an error. - * Here primary plane is being disable so blank the screen - * target display unit, if not already done. - */ + /* Blank STDU when fb and crtc are NULL */ if (!stdu->defined) return; @@ -1340,36 +1651,25 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, return; } + /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ event = crtc->state->event; - /* - * In case of failure and other cases, vblank event will be sent in - * vmw_du_crtc_atomic_flush. - */ - if (event && (ret == 0)) { - struct vmw_fence_obj *fence = NULL; + if (event && fence) { struct drm_file *file_priv = event->base.file_priv; - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - - /* - * If fence is NULL, then already sync. - */ - if (fence) { - ret = vmw_event_fence_action_queue( - file_priv, fence, &event->base, - &event->event.vbl.tv_sec, - &event->event.vbl.tv_usec, - true); - if (ret) - DRM_ERROR("Failed to queue event on fence.\n"); - else - crtc->state->event = NULL; - - vmw_fence_obj_unreference(&fence); - } - } else { - (void) vmw_fifo_flush(dev_priv, false); + ret = vmw_event_fence_action_queue(file_priv, + fence, + &event->base, + &event->event.vbl.tv_sec, + &event->event.vbl.tv_usec, + true); + if (ret) + DRM_ERROR("Failed to queue event on fence.\n"); + else + crtc->state->event = NULL; } + + if (fence) + vmw_fence_obj_unreference(&fence); } @@ -1457,11 +1757,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) stdu->base.pref_active = (unit == 0); stdu->base.pref_width = dev_priv->initial_width; stdu->base.pref_height = dev_priv->initial_height; - - /* - * Remove this after enabling atomic because property values can - * only exist in a state object - */ stdu->base.is_implicit = false; /* Initialize primary plane */ @@ -1478,6 +1773,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) } drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary); /* Initialize cursor plane */ vmw_du_plane_reset(cursor); @@ -1506,7 +1802,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); connector->status = vmw_du_connector_detect(connector, false); - vmw_connector_state_to_vcs(connector->state)->is_implicit = false; ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); @@ -1544,11 +1839,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.suggested_y_property, 0); - if (dev_priv->implicit_placement_property) - drm_object_attach_property - (&connector->base, - dev_priv->implicit_placement_property, - stdu->base.is_implicit); return 0; err_free_unregister: @@ -1617,8 +1907,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) dev_priv->active_display_unit = vmw_du_screen_target; - vmw_kms_create_implicit_placement_property(dev_priv, false); - for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { ret = vmw_stdu_init(dev_priv, i); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index 7b1e5a5cbd2c..e6d75e377dd8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -43,56 +43,38 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) return ttm_bo_mmap(filp, vma, &dev_priv->bdev); } -static int vmw_ttm_mem_global_init(struct drm_global_reference *ref) +/* struct vmw_validation_mem callback */ +static int vmw_vmt_reserve(struct vmw_validation_mem *m, size_t size) { - DRM_INFO("global init.\n"); - return ttm_mem_global_init(ref->object); -} + static struct ttm_operation_ctx ctx = {.interruptible = false, + .no_wait_gpu = false}; + struct vmw_private *dev_priv = container_of(m, struct vmw_private, vvm); -static void vmw_ttm_mem_global_release(struct drm_global_reference *ref) -{ - ttm_mem_global_release(ref->object); + return ttm_mem_global_alloc(vmw_mem_glob(dev_priv), size, &ctx); } -int vmw_ttm_global_init(struct vmw_private *dev_priv) +/* struct vmw_validation_mem callback */ +static void vmw_vmt_unreserve(struct vmw_validation_mem *m, size_t size) { - struct drm_global_reference *global_ref; - int ret; - - global_ref = &dev_priv->mem_global_ref; - global_ref->global_type = DRM_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 = drm_global_item_ref(global_ref); - if (unlikely(ret != 0)) { - DRM_ERROR("Failed setting up TTM memory accounting.\n"); - return ret; - } + struct vmw_private *dev_priv = container_of(m, struct vmw_private, vvm); - 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 = DRM_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 = drm_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: - drm_global_item_unref(&dev_priv->mem_global_ref); - return ret; + return ttm_mem_global_free(vmw_mem_glob(dev_priv), size); } -void vmw_ttm_global_release(struct vmw_private *dev_priv) +/** + * vmw_validation_mem_init_ttm - Interface the validation memory tracker + * to ttm. + * @dev_priv: Pointer to struct vmw_private. The reason we choose a vmw private + * rather than a struct vmw_validation_mem is to make sure assumption in the + * callbacks that struct vmw_private derives from struct vmw_validation_mem + * holds true. + * @gran: The recommended allocation granularity + */ +void vmw_validation_mem_init_ttm(struct vmw_private *dev_priv, size_t gran) { - drm_global_item_unref(&dev_priv->bo_global_ref.ref); - drm_global_item_unref(&dev_priv->mem_global_ref); + struct vmw_validation_mem *vvm = &dev_priv->vvm; + + vvm->reserve_mem = vmw_vmt_reserve; + vvm->unreserve_mem = vmw_vmt_unreserve; + vvm->gran = gran; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c index 184025fa938e..b3f547fc5d3d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c @@ -104,11 +104,25 @@ void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, return NULL; if (ctx->mem_size_left < size) { - struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO); + struct page *page; + if (ctx->vm && ctx->vm_size_left < PAGE_SIZE) { + int ret = ctx->vm->reserve_mem(ctx->vm, ctx->vm->gran); + + if (ret) + return NULL; + + ctx->vm_size_left += ctx->vm->gran; + ctx->total_mem += ctx->vm->gran; + } + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (!page) return NULL; + if (ctx->vm) + ctx->vm_size_left -= PAGE_SIZE; + list_add_tail(&page->lru, &ctx->page_list); ctx->page_address = page_address(page); ctx->mem_size_left = PAGE_SIZE; @@ -138,6 +152,11 @@ static void vmw_validation_mem_free(struct vmw_validation_context *ctx) } ctx->mem_size_left = 0; + if (ctx->vm && ctx->total_mem) { + ctx->vm->unreserve_mem(ctx->vm, ctx->total_mem); + ctx->total_mem = 0; + ctx->vm_size_left = 0; + } } /** @@ -266,7 +285,7 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx, val_buf->bo = ttm_bo_get_unless_zero(&vbo->base); if (!val_buf->bo) return -ESRCH; - val_buf->shared = false; + val_buf->num_shared = 0; list_add_tail(&val_buf->head, &ctx->bo_list); bo_node->as_mob = as_mob; bo_node->cpu_blit = cpu_blit; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h index b57e3292c386..3b396fea40d7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h @@ -34,6 +34,21 @@ #include <drm/ttm/ttm_execbuf_util.h> /** + * struct vmw_validation_mem - Custom interface to provide memory reservations + * for the validation code. + * @reserve_mem: Callback to reserve memory + * @unreserve_mem: Callback to unreserve memory + * @gran: Reservation granularity. Contains a hint how much memory should + * be reserved in each call to @reserve_mem(). A slow implementation may want + * reservation to be done in large batches. + */ +struct vmw_validation_mem { + int (*reserve_mem)(struct vmw_validation_mem *m, size_t size); + void (*unreserve_mem)(struct vmw_validation_mem *m, size_t size); + size_t gran; +}; + +/** * struct vmw_validation_context - Per command submission validation context * @ht: Hash table used to find resource- or buffer object duplicates * @resource_list: List head for resource validation metadata @@ -47,6 +62,10 @@ * buffer objects * @mem_size_left: Free memory left in the last page in @page_list * @page_address: Kernel virtual address of the last page in @page_list + * @vm: A pointer to the memory reservation interface or NULL if no + * memory reservation is needed. + * @vm_size_left: Amount of reserved memory that so far has not been allocated. + * @total_mem: Amount of reserved memory. */ struct vmw_validation_context { struct drm_open_hash *ht; @@ -59,6 +78,9 @@ struct vmw_validation_context { unsigned int merge_dups; unsigned int mem_size_left; u8 *page_address; + struct vmw_validation_mem *vm; + size_t vm_size_left; + size_t total_mem; }; struct vmw_buffer_object; @@ -102,6 +124,21 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx) } /** + * vmw_validation_set_val_mem - Register a validation mem object for + * validation memory reservation + * @ctx: The validation context + * @vm: Pointer to a struct vmw_validation_mem + * + * Must be set before the first attempt to allocate validation memory. + */ +static inline void +vmw_validation_set_val_mem(struct vmw_validation_context *ctx, + struct vmw_validation_mem *vm) +{ + ctx->vm = vm; +} + +/** * vmw_validation_set_ht - Register a hash table for duplicate finding * @ctx: The validation context * @ht: Pointer to a hash table to use for duplicate finding |