From e41774c08ede53d96501f28f68645107f232960d Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 11 Jul 2018 15:42:45 -0700 Subject: drm/vmwgfx: Add a new interface for plane update on a display unit Add a new struct vmw_du_update_plane similar to vmw_kms_dirty which represent the flow of operations needed to update a display unit from surface or bo (blit a new framebuffer). v2: - Kernel doc correction. - Rebase. v3: Rebase to new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 122 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 111 ++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index e6b11f6ae2e4..a2c0a95798f2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) @@ -2935,3 +2936,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..f2f57e58dd88 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -33,7 +33,101 @@ #include #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_kms_dirty - closure structure for the vmw_kms_helper_dirty @@ -458,4 +552,21 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, 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 -- cgit v1.2.3 From ad377b433b8072861be86ba435944c8a42a20228 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 11 Jul 2018 16:25:19 -0700 Subject: drm/vmwgfx: Implement STDU plane update for surface backed fb Using the new interface implement STDU plane update for surface backed fb. v2: Rebase to new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 182 ++++++++++++++++++++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index c3e435f444c1..86368c5b778d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -30,7 +30,7 @@ #include #include #include - +#include #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 @@ -1256,7 +1260,183 @@ out_srf_unref: return ret; } +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_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 -- cgit v1.2.3 From bc7be607a0edc1bf1ea403efbdd0fe81a71dc369 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Mon, 9 Jul 2018 16:17:17 -0700 Subject: drm/vmwgfx: Implement STDU plane update for BO backed fb Using the new interface implement STDU plane update for BO backed fb. v2: Rebase to new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 11 ++ drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 216 +++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index f2f57e58dd88..73fc51f43400 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -129,6 +129,17 @@ struct vmw_du_update_plane { bool intr; }; +/** + * 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 * function. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 86368c5b778d..e976aa0235e6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1260,6 +1260,222 @@ 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) -- cgit v1.2.3 From 4606eeaf679b796c98a9fe69f324c7ddfab35409 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 21 Sep 2018 13:42:35 -0700 Subject: drm/vmwgfx: Use the new interface for STDU plane update With new interface to do plane update on STDU available, use that instead of old kms_dirty. v2: Use fence from new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 54 +++++++++++++----------------------- 1 file changed, 20 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index e976aa0235e6..0dcaec59ebe8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1673,6 +1673,7 @@ 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; @@ -1683,7 +1684,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, 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); @@ -1691,23 +1691,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 { @@ -1740,31 +1734,23 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, * 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); } -- cgit v1.2.3 From 88b37c3ae769beb9f0b2a15604788a497211ad45 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 21 Sep 2018 13:46:42 -0700 Subject: drm/vmwgfx: Update comments for stdu plane update Update the comments to sync with code. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 0dcaec59ebe8..f6f788b4a19d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1656,7 +1656,6 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, /** * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane - * * @plane: display plane * @old_state: Only used to get crtc info * @@ -1677,10 +1676,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, 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); @@ -1709,12 +1705,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; @@ -1729,11 +1720,8 @@ 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 && fence) { struct drm_file *file_priv = event->base.file_priv; -- cgit v1.2.3 From 8bb6af5b0cbec157e1481d66d562f4752d28d361 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 27 Jul 2018 17:28:17 -0700 Subject: drm/vmwgfx: Enable FB_DAMAGE_CLIPS property for STDU primary plane STDU primary plane now support damage clips, enable it for user-space. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index f6f788b4a19d..4a060e6e8297 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1847,6 +1847,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); -- cgit v1.2.3 From 43d1e627144ae1bf8de778a583bdf77c2e521cb3 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 8 Aug 2018 12:39:31 -0700 Subject: drm/vmwgfx: Implement SOU plane update for surface backed fb Using the new interface implement SOU plane update for surface backed fb. v2: Rebase to new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 11 +++ drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 161 +++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 73fc51f43400..3e8b8b3d33aa 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -129,6 +129,17 @@ struct vmw_du_update_plane { 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. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 333418dc259f..c9a09c96642d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -498,6 +498,167 @@ 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_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, -- cgit v1.2.3 From 5d35abade40d34368838a7b389c3613073b8273c Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 8 Aug 2018 15:02:48 -0700 Subject: drm/vmwgfx: Implement SOU plane update for BO backed fb Using the new interface implement SOU plane update for BO backed fb. v2: Rebase to new resource validation. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c9a09c96642d..670f4ac5cdd3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -76,6 +76,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. */ @@ -498,6 +503,102 @@ 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) { -- cgit v1.2.3 From 67a51b3d9889978d3086f9e63bdabe157af428ff Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 21 Sep 2018 14:07:33 -0700 Subject: drm/vmwgfx: Use the new interface for SOU plane update With new interface to do plane update on SOU available, use that instead of old kms_dirty. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 670f4ac5cdd3..0bca79caf96a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -774,21 +774,14 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, 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); + ret = vmw_sou_plane_update_surface(dev_priv, plane, + old_state, vfb, + &fence); /* * We cannot really fail this function, so if we do, then output -- cgit v1.2.3 From 31da2df8ce18556a9ebe78f6626661da962940ad Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 21 Sep 2018 14:10:35 -0700 Subject: drm/vmwgfx: Update comments for sou plane update function Update comments to sync with code. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 0bca79caf96a..5a193eb6c4b8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -770,6 +770,7 @@ 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 = @@ -782,28 +783,15 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, ret = vmw_sou_plane_update_surface(dev_priv, plane, old_state, vfb, &fence); - - /* - * We cannot really fail this function, so if we do, then output - * an error and maintain consistent atomic state. - */ 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; -- cgit v1.2.3 From 61c21387c8b3191b1e74d01cab902c9b3493beb0 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 8 Aug 2018 15:41:56 -0700 Subject: drm/vmwgfx: Enable FB_DAMAGE_CLIPS property for SOU primary plane SOU primary plane now support damage clips, enable it for user-space. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 5a193eb6c4b8..7a1187e56ce6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -29,6 +29,7 @@ #include #include #include +#include #define vmw_crtc_to_sou(x) \ @@ -908,6 +909,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); -- cgit v1.2.3 From 2f5544ff030040a1016277cb91c347a64568b597 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Fri, 21 Sep 2018 14:34:02 -0700 Subject: drm/vmwgfx: Use atomic helper function for dirty fb IOCTL USe new atomic helper for dirty fb IOCTL which make use of damage interface. Note that this is only done for STDU and SOU, for legacy display unit still using old interface. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 82 ++++++++----------------------------- 1 file changed, 18 insertions(+), 64 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a2c0a95798f2..21228b3b1ed7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -847,58 +847,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. @@ -942,7 +890,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, @@ -1085,16 +1033,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); @@ -1113,9 +1051,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, }; /** -- cgit v1.2.3 From b4fa61ba05f2afa17558914fdd2b819e9e7e466f Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 26 Sep 2018 17:17:33 -0700 Subject: drm/vmwgfx: Don't clear mode::type anymore With kernel commit "drm/modes: Kill off the oddball DRM_MODE_TYPE_CRTC_C vs. DRM_MODE_TYPE_BUILTIN handling", no need to clear mode::type for user-space bug. Signed-off-by: Deepak Rawat Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 22 ---------------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 3 --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 +- 5 files changed, 3 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 21228b3b1ed7..d8573e7e8533 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2812,28 +2812,6 @@ vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, } - -/** - * 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. * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 3e8b8b3d33aa..bc5bccf1db42 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -572,9 +572,6 @@ 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); /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 4b5378495eea..aa083ac0dc18 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, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 7a1187e56ce6..eb4c94fe1044 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -353,7 +353,7 @@ static const struct drm_crtc_funcs vmw_screen_object_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, .page_flip = vmw_sou_crtc_page_flip, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 4a060e6e8297..9f645aa00c48 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -990,7 +990,7 @@ 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, + .set_config = drm_atomic_helper_set_config, .page_flip = vmw_stdu_crtc_page_flip, }; -- cgit v1.2.3 From 9d9486e43728cd513e10ed3dd54e156c8ab7bd2a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 4 Oct 2018 22:38:17 +0000 Subject: drm/vmwgfx: Fix up the implicit display unit handling Make the connector is_implicit property immutable. As far as we know, no user-space application is writing to it. Also move the verification that all implicit display units scan out from the same framebuffer to atomic_check(). Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Reviewed-by: Deepak Rawat --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 277 +++++++++++------------------------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 16 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 9 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 41 +----- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 46 +----- 6 files changed, 99 insertions(+), 292 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 28df788da44e..5fbe47a52609 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -484,8 +484,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; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index d8573e7e8533..43ee7ccca418 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -457,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); } @@ -1519,6 +1506,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, return 0; } +/** + * 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 @@ -1636,6 +1705,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; @@ -2230,84 +2303,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 @@ -2696,120 +2691,24 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, return ret; } -/** - * 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); - } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index bc5bccf1db42..655abbcd4058 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -307,8 +307,6 @@ struct vmw_plane_state { struct vmw_connector_state { struct drm_connector_state base; - bool is_implicit; - /** * @gui_x: * @@ -370,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; }; @@ -450,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); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index aa083ac0dc18..16be515c4c0f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -263,13 +263,10 @@ 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 @@ -416,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); @@ -427,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); @@ -447,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, @@ -513,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_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index eb4c94fe1044..8e5eecdf148a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -247,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); - - x = vmw_conn_state->gui_x; - y = vmw_conn_state->gui_y; - } + 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; 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); } } @@ -329,21 +321,14 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, 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; } @@ -383,13 +368,10 @@ 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, }; @@ -883,7 +865,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; @@ -937,8 +918,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); @@ -977,12 +956,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: @@ -1008,15 +981,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 9f645aa00c48..26a3515ae718 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -400,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); @@ -421,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, @@ -501,11 +478,10 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, 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)) + if (!stdu->defined) return -EINVAL; ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); @@ -1046,13 +1022,10 @@ 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, }; @@ -1826,11 +1799,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 */ @@ -1876,7 +1844,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); @@ -1914,11 +1881,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: @@ -1987,8 +1949,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); -- cgit v1.2.3 From 9da6e26c0aae3fda6017c1ecf5c8881f8dbc37df Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 12 Nov 2018 15:46:39 +0100 Subject: drm/vmwgfx: Fix a layout race condition This fixes a layout update race condition. We make sure the crtc mutex is locked before we dereference crtc->state. Otherwise the state might change under us. Since now we're already holding the crtc mutexes when reading the gui coordinates, protect them with the crtc mutexes rather than with the requested_layout mutex. Signed-off-by: Thomas Hellstrom Reviewed-by: Deepak Rawat Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 ----- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 66 ++++++++++++++++++++++--------------- 3 files changed, 39 insertions(+), 37 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index b9c078860a7c..9fd8b4e75a8c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -665,7 +665,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); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5fbe47a52609..d7f6cb9331de 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -465,15 +465,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. */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 43ee7ccca418..b351fb5214d3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1599,7 +1599,6 @@ static int vmw_kms_check_implicit(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; @@ -1611,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; } } @@ -1635,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; @@ -1663,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; } @@ -2031,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); @@ -2054,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) { @@ -2076,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; } -- cgit v1.2.3 From ec9a5b611e2fde765372885220555a5b38e13c09 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 4 Oct 2018 18:49:53 +0100 Subject: drm/vmwgfx: remove redundant return ret statement The return statement is redundant as there is a return statement immediately before it so we have dead code that can be removed. Also remove the unused declaration of ret. Detected by CoverityScan, CID#1473793 ("Structurally dead code") Signed-off-by: Colin Ian King Reviewed-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 5a6b70ba137a..260650bb5560 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; } -- cgit v1.2.3 From e5bd6a3dddda58b0b5a246b35faadd844b0ff574 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 11:36:58 +0000 Subject: drm/vmwgfx: Remove set but not used variable 'file_priv' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/vmwgfx/vmwgfx_fence.c: In function 'vmw_event_fence_action_seq_passed': drivers/gpu/drm/vmwgfx/vmwgfx_fence.c:909:19: warning: variable 'file_priv' set but not used [-Wunused-but-set-variable] struct drm_file *file_priv; It not used any more since commit fb740cf2492c ("drm: Create drm_send_event helpers") Signed-off-by: YueHaibing Reviewed-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') 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)) { -- cgit v1.2.3 From 9a01135b98b9d5a7033c544245da7aad0d886758 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 14 Nov 2018 08:11:05 +0100 Subject: drm/vmwgfx: Use the standard atomic helpers for page-flip Our wrappers don't do anything useful anymore except calling the atomic helpers. Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 19 +--------------- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 44 +----------------------------------- 2 files changed, 2 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/vmwgfx') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 8e5eecdf148a..cd586c52af7e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -315,23 +315,6 @@ 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) -{ - int ret; - - 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 ret; -} - static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_sou_crtc_destroy, @@ -339,7 +322,7 @@ static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, - .page_flip = vmw_sou_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, }; /* diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 26a3515ae718..096c2941a8e4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -452,48 +452,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_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); - int ret; - - if (!stdu->defined) - 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 * @@ -967,7 +925,7 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, - .page_flip = vmw_stdu_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, }; -- cgit v1.2.3