diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 809 |
1 files changed, 300 insertions, 509 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 096c2941a8e4..20aab725e53a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /****************************************************************************** * - * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright (c) 2014-2024 Broadcom. All Rights Reserved. The term + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -25,12 +26,17 @@ * ******************************************************************************/ +#include "vmwgfx_bo.h" #include "vmwgfx_kms.h" -#include "device_include/svga3d_surfacedefs.h" -#include <drm/drm_plane_helper.h> +#include "vmwgfx_vkms.h" +#include "vmw_surface_cache.h" +#include <linux/fsnotify.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_vblank.h> #define vmw_crtc_to_stdu(x) \ container_of(x, struct vmw_screen_target_display_unit, base.crtc) @@ -39,7 +45,14 @@ #define vmw_connector_to_stdu(x) \ container_of(x, struct vmw_screen_target_display_unit, base.connector) - +/* + * Some renderers such as llvmpipe will align the width and height of their + * buffers to match their tile size. We need to keep this in mind when exposing + * modes to userspace so that this possible over-allocation will not exceed + * graphics memory. 64x64 pixels seems to be a reasonable upper bound for the + * tile size of current renderers. + */ +#define GPU_TILE_SIZE 64 enum stdu_content_type { SAME_AS_DISPLAY = 0, @@ -51,24 +64,23 @@ enum stdu_content_type { * struct vmw_stdu_dirty - closure structure for the update functions * * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). - * @transfer: Transfer direction for DMA command. * @left: Left side of bounding box. * @right: Right side of bounding box. * @top: Top side of bounding box. * @bottom: Bottom side of bounding box. * @fb_left: Left side of the framebuffer/content bounding box * @fb_top: Top of the framebuffer/content bounding box + * @pitch: framebuffer pitch (stride) * @buf: buffer object when DMA-ing between buffer and screen targets. * @sid: Surface ID when copying between surface and screen targets. */ struct vmw_stdu_dirty { struct vmw_kms_dirty base; - SVGA3dTransferType transfer; s32 left, right, top, bottom; s32 fb_left, fb_top; u32 pitch; union { - struct vmw_buffer_object *buf; + struct vmw_bo *buf; u32 sid; }; }; @@ -82,11 +94,6 @@ struct vmw_stdu_update { SVGA3dCmdUpdateGBScreenTarget body; }; -struct vmw_stdu_dma { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceDMA body; -}; - struct vmw_stdu_surface_copy { SVGA3dCmdHeader header; SVGA3dCmdSurfaceCopy body; @@ -98,7 +105,7 @@ struct vmw_stdu_update_gb_image { }; /** - * struct vmw_screen_target_display_unit + * struct vmw_screen_target_display_unit - conglomerated STDU structure * * @base: VMW specific DU structure * @display_srf: surface to be displayed. The dimension of this will always @@ -106,12 +113,15 @@ struct vmw_stdu_update_gb_image { * content_vfbs dimensions, then this is a pointer into the * corresponding field in content_vfbs. If not, then this * is a separate buffer to which content_vfbs will blit to. - * @content_type: content_fb type - * @defined: true if the current display unit has been initialized + * @content_fb_type: content_fb type + * @display_width: display width + * @display_height: display height + * @defined: true if the current display unit has been initialized + * @cpp: Bytes per pixel */ struct vmw_screen_target_display_unit { struct vmw_display_unit base; - const struct vmw_surface *display_srf; + struct vmw_surface *display_srf; enum stdu_content_type content_fb_type; s32 display_width, display_height; @@ -131,7 +141,6 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); * Screen Target Display Unit CRTC Functions *****************************************************************************/ - /** * vmw_stdu_crtc_destroy - cleans up the STDU * @@ -167,12 +176,9 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, SVGA3dCmdDefineGBScreenTarget body; } *cmd; - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - - if (unlikely(cmd == NULL)) { - DRM_ERROR("Out of FIFO space defining Screen Target\n"); + cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) return -ENOMEM; - } cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET; cmd->header.size = sizeof(cmd->body); @@ -188,7 +194,7 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, stdu->base.set_gui_x = cmd->body.xRoot; stdu->base.set_gui_y = cmd->body.yRoot; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + vmw_cmd_commit(dev_priv, sizeof(*cmd)); stdu->defined = true; stdu->display_width = mode->hdisplay; @@ -207,6 +213,8 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, * @res: Buffer to bind to the screen target. Set to NULL to blank screen. * * Binding a surface to a Screen Target the same as flipping + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu, @@ -229,12 +237,9 @@ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, memset(&image, 0, sizeof(image)); image.sid = res ? res->id : SVGA3D_INVALID_ID; - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - - if (unlikely(cmd == NULL)) { - DRM_ERROR("Out of FIFO space binding a screen target\n"); + cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) return -ENOMEM; - } cmd->header.id = SVGA_3D_CMD_BIND_GB_SCREENTARGET; cmd->header.size = sizeof(cmd->body); @@ -242,7 +247,7 @@ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, cmd->body.stid = stdu->base.unit; cmd->body.image = image; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + vmw_cmd_commit(dev_priv, sizeof(*cmd)); return 0; } @@ -296,18 +301,15 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, return -EINVAL; } - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - - if (unlikely(cmd == NULL)) { - DRM_ERROR("Out of FIFO space updating a Screen Target\n"); + cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) return -ENOMEM; - } vmw_stdu_populate_update(cmd, stdu->base.unit, 0, stdu->display_width, 0, stdu->display_height); - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + vmw_cmd_commit(dev_priv, sizeof(*cmd)); return 0; } @@ -319,6 +321,9 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, * * @dev_priv: VMW DRM device * @stdu: display unit to destroy + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. */ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu) @@ -335,19 +340,16 @@ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, if (unlikely(!stdu->defined)) return 0; - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - - if (unlikely(cmd == NULL)) { - DRM_ERROR("Out of FIFO space, screen target not destroyed\n"); + cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) return -ENOMEM; - } cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET; cmd->header.size = sizeof(cmd->body); cmd->body.stid = stdu->base.unit; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + vmw_cmd_commit(dev_priv, sizeof(*cmd)); /* Force sync */ ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); @@ -411,24 +413,14 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) crtc->x, crtc->y); } - -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) -{ -} - static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_atomic_state *state) { struct vmw_private *dev_priv; struct vmw_screen_target_display_unit *stdu; + struct drm_crtc_state *new_crtc_state; int ret; - if (!crtc) { DRM_ERROR("CRTC is NULL\n"); return; @@ -436,6 +428,10 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + if (dev_priv->vkms_enabled) + drm_crtc_vblank_off(crtc); if (stdu->defined) { ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); @@ -444,6 +440,14 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, (void) vmw_stdu_update_st(dev_priv, stdu); + /* Don't destroy the Screen Target if we are only setting the + * display as inactive + */ + if (new_crtc_state->enable && + !new_crtc_state->active && + !new_crtc_state->mode_changed) + return; + ret = vmw_stdu_destroy_st(dev_priv, stdu); if (ret) DRM_ERROR("Failed to destroy Screen Target\n"); @@ -453,92 +457,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, } /** - * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect - * - * @dirty: The closure structure. - * - * Encodes a surface DMA command cliprect and updates the bounding box - * for the DMA. - */ -static void vmw_stdu_bo_clip(struct vmw_kms_dirty *dirty) -{ - struct vmw_stdu_dirty *ddirty = - container_of(dirty, struct vmw_stdu_dirty, base); - struct vmw_stdu_dma *cmd = dirty->cmd; - struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; - - blit += dirty->num_hits; - blit->srcx = dirty->fb_x; - blit->srcy = dirty->fb_y; - blit->x = dirty->unit_x1; - blit->y = dirty->unit_y1; - blit->d = 1; - blit->w = dirty->unit_x2 - dirty->unit_x1; - blit->h = dirty->unit_y2 - dirty->unit_y1; - dirty->num_hits++; - - if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) - return; - - /* Destination bounding box */ - ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1); - ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1); - ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2); - ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2); -} - -/** - * vmw_stdu_bo_fifo_commit - Callback to fill in and submit a DMA command. - * - * @dirty: The closure structure. - * - * Fills in the missing fields in a DMA command, and optionally encodes - * a screen target update command, depending on transfer direction. - */ -static void vmw_stdu_bo_fifo_commit(struct vmw_kms_dirty *dirty) -{ - struct vmw_stdu_dirty *ddirty = - container_of(dirty, struct vmw_stdu_dirty, base); - struct vmw_screen_target_display_unit *stdu = - container_of(dirty->unit, typeof(*stdu), base); - struct vmw_stdu_dma *cmd = dirty->cmd; - struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; - SVGA3dCmdSurfaceDMASuffix *suffix = - (SVGA3dCmdSurfaceDMASuffix *) &blit[dirty->num_hits]; - size_t blit_size = sizeof(*blit) * dirty->num_hits + sizeof(*suffix); - - if (!dirty->num_hits) { - vmw_fifo_commit(dirty->dev_priv, 0); - return; - } - - cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; - cmd->header.size = sizeof(cmd->body) + blit_size; - vmw_bo_get_guest_ptr(&ddirty->buf->base, &cmd->body.guest.ptr); - cmd->body.guest.pitch = ddirty->pitch; - cmd->body.host.sid = stdu->display_srf->res.id; - cmd->body.host.face = 0; - cmd->body.host.mipmap = 0; - cmd->body.transfer = ddirty->transfer; - suffix->suffixSize = sizeof(*suffix); - suffix->maximumOffset = ddirty->buf->base.num_pages * PAGE_SIZE; - - if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { - blit_size += sizeof(struct vmw_stdu_update); - - vmw_stdu_populate_update(&suffix[1], stdu->base.unit, - ddirty->left, ddirty->right, - ddirty->top, ddirty->bottom); - } - - vmw_fifo_commit(dirty->dev_priv, sizeof(*cmd) + blit_size); - - ddirty->left = ddirty->top = S32_MAX; - ddirty->right = ddirty->bottom = S32_MIN; -} - - -/** * vmw_stdu_bo_cpu_clip - Callback to encode a CPU blit * * @dirty: The closure structure. @@ -584,7 +502,7 @@ static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) container_of(dirty->unit, typeof(*stdu), base); s32 width, height; s32 src_pitch, dst_pitch; - struct ttm_buffer_object *src_bo, *dst_bo; + struct vmw_bo *src_bo, *dst_bo; u32 src_offset, dst_offset; struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp); @@ -598,141 +516,85 @@ static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) return; /* Assume we are blitting from Guest (bo) to Host (display_srf) */ - dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; - dst_bo = &stdu->display_srf->res.backup->base; - dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; - - src_pitch = ddirty->pitch; - src_bo = &ddirty->buf->base; - src_offset = ddirty->fb_top * src_pitch + ddirty->fb_left * stdu->cpp; - - /* Swap src and dst if the assumption was wrong. */ - if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) { - swap(dst_pitch, src_pitch); - swap(dst_bo, src_bo); - swap(src_offset, dst_offset); - } + src_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; + src_bo = stdu->display_srf->res.guest_memory_bo; + src_offset = ddirty->top * src_pitch + ddirty->left * stdu->cpp; + + dst_pitch = ddirty->pitch; + dst_bo = ddirty->buf; + dst_offset = ddirty->fb_top * dst_pitch + ddirty->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 (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM && - drm_rect_visible(&diff.rect)) { - struct vmw_private *dev_priv; - struct vmw_stdu_update *cmd; - struct drm_clip_rect region; - int ret; - - /* We are updating the actual surface, not a proxy */ - region.x1 = diff.rect.x1; - region.x2 = diff.rect.x2; - region.y1 = diff.rect.y1; - region.y2 = diff.rect.y2; - ret = vmw_kms_update_proxy( - (struct vmw_resource *) &stdu->display_srf->res, - (const struct drm_clip_rect *) ®ion, 1, 1); - if (ret) - goto out_cleanup; - - - dev_priv = vmw_priv(stdu->base.crtc.dev); - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - - if (!cmd) { - DRM_ERROR("Cannot reserve FIFO space to update STDU"); - goto out_cleanup; - } - - vmw_stdu_populate_update(cmd, stdu->base.unit, - region.x1, region.x2, - region.y1, region.y2); - - vmw_fifo_commit(dev_priv, sizeof(*cmd)); - } - -out_cleanup: - ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; - ddirty->right = ddirty->bottom = S32_MIN; } /** - * vmw_kms_stdu_dma - Perform a DMA transfer between a buffer-object backed + * vmw_kms_stdu_readback - Perform a readback from a buffer-object backed * framebuffer and the screen target system. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm-file identifying the caller. May be * set to NULL, but then @user_fence_rep must also be set to NULL. * @vfb: Pointer to the buffer-object backed framebuffer. + * @user_fence_rep: User-space provided structure for fence information. * @clips: Array of clip rects. Either @clips or @vclips must be NULL. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. * @num_clips: Number of clip rects in @clips or @vclips. * @increment: Increment to use when looping over @clips or @vclips. - * @to_surface: Whether to DMA to the screen target system as opposed to - * from the screen target system. - * @interruptible: Whether to perform waits interruptible if possible. * @crtc: If crtc is passed, perform stdu dma on that crtc only. * * If DMA-ing till the screen target system, the function will also notify * the screen target system that a bounding box of the cliprects has been * updated. - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ -int vmw_kms_stdu_dma(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - struct drm_vmw_fence_rep __user *user_fence_rep, - struct drm_clip_rect *clips, - struct drm_vmw_rect *vclips, - uint32_t num_clips, - int increment, - bool to_surface, - bool interruptible, - struct drm_crtc *crtc) +int vmw_kms_stdu_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + uint32_t num_clips, + int increment, + struct drm_crtc *crtc) { - struct vmw_buffer_object *buf = + struct vmw_bo *buf = container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_stdu_dirty ddirty; int ret; - bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); /* - * VMs without 3D support don't have the surface DMA command and - * we'll be using a CPU blit, and the framebuffer should be moved out - * of VRAM. + * The GMR domain might seem confusing because it might seem like it should + * never happen with screen targets but e.g. the xorg vmware driver issues + * CMD_SURFACE_DMA for various pixmap updates which might transition our bo to + * a GMR. Instead of forcing another transition we can optimize the readback + * by reading directly from the GMR. */ - ret = vmw_validation_add_bo(&val_ctx, buf, false, cpu_blit); + vmw_bo_placement_set(buf, + VMW_BO_DOMAIN_MOB | VMW_BO_DOMAIN_SYS | VMW_BO_DOMAIN_GMR, + VMW_BO_DOMAIN_MOB | VMW_BO_DOMAIN_SYS | VMW_BO_DOMAIN_GMR); + ret = vmw_validation_add_bo(&val_ctx, buf); if (ret) return ret; - ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); + ret = vmw_validation_prepare(&val_ctx, NULL, true); if (ret) goto out_unref; - ddirty.transfer = (to_surface) ? SVGA3D_WRITE_HOST_VRAM : - SVGA3D_READ_HOST_VRAM; ddirty.left = ddirty.top = S32_MAX; ddirty.right = ddirty.bottom = S32_MIN; ddirty.fb_left = ddirty.fb_top = S32_MAX; ddirty.pitch = vfb->base.pitches[0]; ddirty.buf = buf; - ddirty.base.fifo_commit = vmw_stdu_bo_fifo_commit; - ddirty.base.clip = vmw_stdu_bo_clip; - ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) + - num_clips * sizeof(SVGA3dCopyBox) + - sizeof(SVGA3dCmdSurfaceDMASuffix); - if (to_surface) - ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); - - - if (cpu_blit) { - ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit; - ddirty.base.clip = vmw_stdu_bo_cpu_clip; - ddirty.base.fifo_reserve_size = 0; - } + + ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit; + ddirty.base.clip = vmw_stdu_bo_cpu_clip; + ddirty.base.fifo_reserve_size = 0; ddirty.base.crtc = crtc; @@ -749,7 +611,7 @@ out_unref: } /** - * vmw_stdu_surface_clip - Callback to encode a surface copy command cliprect + * vmw_kms_stdu_surface_clip - Callback to encode a surface copy command cliprect * * @dirty: The closure structure. * @@ -787,7 +649,7 @@ static void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_stdu_surface_fifo_commit - Callback to fill in and submit a surface + * vmw_kms_stdu_surface_fifo_commit - Callback to fill in and submit a surface * copy command. * * @dirty: The closure structure. @@ -807,7 +669,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) size_t commit_size; if (!dirty->num_hits) { - vmw_fifo_commit(dirty->dev_priv, 0); + vmw_cmd_commit(dirty->dev_priv, 0); return; } @@ -820,6 +682,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) cmd->body.dest.sid = stdu->display_srf->res.id; update = (struct vmw_stdu_update *) &blit[dirty->num_hits]; commit_size = sizeof(*cmd) + blit_size + sizeof(*update); + stdu->display_srf->res.res_dirty = true; } else { update = dirty->cmd; commit_size = sizeof(*update); @@ -828,7 +691,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) vmw_stdu_populate_update(update, stdu->base.unit, sdirty->left, sdirty->right, sdirty->top, sdirty->bottom); - vmw_fifo_commit(dirty->dev_priv, commit_size); + vmw_cmd_commit(dirty->dev_priv, commit_size); sdirty->left = sdirty->top = S32_MAX; sdirty->right = sdirty->bottom = S32_MIN; @@ -853,7 +716,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) * case the device has already synchronized. * @crtc: If crtc is passed, perform surface dirty on that crtc only. * - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, @@ -874,9 +737,10 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, int ret; if (!srf) - srf = &vfbs->surface->res; + srf = &vmw_user_object_surface(&vfbs->uo)->res; - ret = vmw_validation_add_resource(&val_ctx, srf, 0, NULL, NULL); + ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, + NULL, NULL); if (ret) return ret; @@ -884,12 +748,6 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, if (ret) goto out_unref; - if (vfbs->is_bo_proxy) { - ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); - if (ret) - goto out_finish; - } - sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit; sdirty.base.clip = vmw_kms_stdu_surface_clip; sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + @@ -903,7 +761,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, dest_x, dest_y, num_clips, inc, &sdirty.base); -out_finish: + vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, NULL); @@ -914,7 +772,6 @@ out_unref: return ret; } - /* * Screen Target CRTC dispatch table */ @@ -926,6 +783,12 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, + .enable_vblank = vmw_vkms_enable_vblank, + .disable_vblank = vmw_vkms_disable_vblank, + .get_vblank_timestamp = vmw_vkms_get_vblank_timestamp, + .get_crc_sources = vmw_vkms_get_crc_sources, + .set_crc_source = vmw_vkms_set_crc_source, + .verify_crc_source = vmw_vkms_verify_crc_source, }; @@ -974,12 +837,76 @@ static void vmw_stdu_connector_destroy(struct drm_connector *connector) vmw_stdu_destroy(vmw_connector_to_stdu(connector)); } +static enum drm_mode_status +vmw_stdu_connector_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + enum drm_mode_status ret; + struct drm_device *dev = connector->dev; + struct vmw_private *dev_priv = vmw_priv(dev); + u64 assumed_cpp = dev_priv->assume_16bpp ? 2 : 4; + /* Align width and height to account for GPU tile over-alignment */ + u64 required_mem = ALIGN(mode->hdisplay, GPU_TILE_SIZE) * + ALIGN(mode->vdisplay, GPU_TILE_SIZE) * + assumed_cpp; + required_mem = ALIGN(required_mem, PAGE_SIZE); + + ret = drm_mode_validate_size(mode, dev_priv->stdu_max_width, + dev_priv->stdu_max_height); + if (ret != MODE_OK) + return ret; + + ret = drm_mode_validate_size(mode, dev_priv->texture_max_width, + dev_priv->texture_max_height); + if (ret != MODE_OK) + return ret; + + if (required_mem > dev_priv->max_primary_mem) + return MODE_MEM; + + if (required_mem > dev_priv->max_mob_pages * PAGE_SIZE) + return MODE_MEM; + + if (required_mem > dev_priv->max_mob_size) + return MODE_MEM; + + return MODE_OK; +} + +/* + * Trigger a modeset if the X,Y position of the Screen Target changes. + * This is needed when multi-mon is cycled. The original Screen Target will have + * the same mode but its relative X,Y position in the topology will change. + */ +static int vmw_stdu_connector_atomic_check(struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct drm_connector_state *conn_state; + struct vmw_screen_target_display_unit *du; + struct drm_crtc_state *new_crtc_state; + + conn_state = drm_atomic_get_connector_state(state, conn); + + if (IS_ERR(conn_state)) + return PTR_ERR(conn_state); + du = vmw_connector_to_stdu(conn); + + if (!conn_state->crtc) + return 0; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (du->base.gui_x != du->base.set_gui_x || + du->base.gui_y != du->base.set_gui_y) + new_crtc_state->mode_changed = true; + + return 0; +} 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, + .fill_modes = drm_helper_probe_single_connector_modes, .destroy = vmw_stdu_connector_destroy, .reset = vmw_du_connector_reset, .atomic_duplicate_state = vmw_du_connector_duplicate_state, @@ -989,6 +916,9 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = { static const struct drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { + .get_modes = vmw_connector_get_modes, + .mode_valid = vmw_stdu_connector_mode_valid, + .atomic_check = vmw_stdu_connector_atomic_check, }; @@ -1015,9 +945,8 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, { struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); - if (vps->surf) + if (vmw_user_object_surface(&vps->uo)) WARN_ON(!vps->pinned); - vmw_du_plane_cleanup_fb(plane, old_state); vps->content_fb_type = SAME_AS_DISPLAY; @@ -1025,7 +954,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, } - /** * vmw_stdu_primary_plane_prepare_fb - Readies the display surface * @@ -1036,7 +964,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, * backed by a buffer object. The display surface is pinned here, and it'll * be unpinned in .cleanup_fb() * - * Returns 0 on success + * Returns: %0 on success */ static int vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, @@ -1048,15 +976,16 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); enum stdu_content_type new_content_type; struct vmw_framebuffer_surface *new_vfbs; - struct drm_crtc *crtc = new_state->crtc; uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h; + struct drm_plane_state *old_state = plane->state; + struct drm_rect rect; int ret; /* No FB to prepare */ if (!new_fb) { - if (vps->surf) { + if (vmw_user_object_surface(&vps->uo)) { WARN_ON(vps->pinned != 0); - vmw_surface_unreference(&vps->surf); + vmw_user_object_unref(&vps->uo); } return 0; @@ -1065,8 +994,9 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, vfb = vmw_framebuffer_to_vfb(new_fb); new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); - if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay && - new_vfbs->surface->base_size.height == vdisplay) + if (new_vfbs && + vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.width == hdisplay && + vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.height == vdisplay) new_content_type = SAME_AS_DISPLAY; else if (vfb->bo) new_content_type = SEPARATE_BO; @@ -1074,12 +1004,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, new_content_type = SEPARATE_SURFACE; if (new_content_type != SAME_AS_DISPLAY) { - struct vmw_surface content_srf; - struct drm_vmw_size display_base_size = {0}; - - display_base_size.width = hdisplay; - display_base_size.height = vdisplay; - display_base_size.depth = 1; + struct vmw_surface_metadata metadata = {0}; /* * If content buffer is a buffer object, then we have to @@ -1089,15 +1014,15 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, switch (new_fb->format->cpp[0]*8) { case 32: - content_srf.format = SVGA3D_X8R8G8B8; + metadata.format = SVGA3D_X8R8G8B8; break; case 16: - content_srf.format = SVGA3D_R5G6B5; + metadata.format = SVGA3D_R5G6B5; break; case 8: - content_srf.format = SVGA3D_P8; + metadata.format = SVGA3D_P8; break; default: @@ -1105,43 +1030,33 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, return -EINVAL; } - content_srf.flags = 0; - content_srf.mip_levels[0] = 1; - content_srf.multisample_count = 0; - content_srf.multisample_pattern = - SVGA3D_MS_PATTERN_NONE; - content_srf.quality_level = SVGA3D_MS_QUALITY_NONE; + metadata.mip_levels[0] = 1; + metadata.num_sizes = 1; + metadata.scanout = true; } else { - content_srf = *new_vfbs->surface; + metadata = vmw_user_object_surface(&new_vfbs->uo)->metadata; } - if (vps->surf) { - struct drm_vmw_size cur_base_size = vps->surf->base_size; + metadata.base_size.width = hdisplay; + metadata.base_size.height = vdisplay; + metadata.base_size.depth = 1; - if (cur_base_size.width != display_base_size.width || - cur_base_size.height != display_base_size.height || - vps->surf->format != content_srf.format) { + if (vmw_user_object_surface(&vps->uo)) { + struct drm_vmw_size cur_base_size = + vmw_user_object_surface(&vps->uo)->metadata.base_size; + + if (cur_base_size.width != metadata.base_size.width || + cur_base_size.height != metadata.base_size.height || + vmw_user_object_surface(&vps->uo)->metadata.format != metadata.format) { WARN_ON(vps->pinned != 0); - vmw_surface_unreference(&vps->surf); + vmw_user_object_unref(&vps->uo); } } - if (!vps->surf) { - ret = vmw_surface_gb_priv_define - (crtc->dev, - /* Kernel visible only */ - 0, - content_srf.flags, - content_srf.format, - true, /* a scanout buffer */ - content_srf.mip_levels[0], - content_srf.multisample_count, - 0, - display_base_size, - content_srf.multisample_pattern, - content_srf.quality_level, - &vps->surf); + if (!vmw_user_object_surface(&vps->uo)) { + ret = vmw_gb_surface_define(dev_priv, &metadata, + &vps->uo.surface); if (ret != 0) { DRM_ERROR("Couldn't allocate STDU surface.\n"); return ret; @@ -1154,18 +1069,19 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, * The only time we add a reference in prepare_fb is if the * state object doesn't have a reference to begin with */ - if (vps->surf) { + if (vmw_user_object_surface(&vps->uo)) { WARN_ON(vps->pinned != 0); - vmw_surface_unreference(&vps->surf); + vmw_user_object_unref(&vps->uo); } - vps->surf = vmw_surface_reference(new_vfbs->surface); + memcpy(&vps->uo, &new_vfbs->uo, sizeof(vps->uo)); + vmw_user_object_ref(&vps->uo); } - if (vps->surf) { + if (vmw_user_object_surface(&vps->uo)) { /* Pin new surface before flipping */ - ret = vmw_resource_pin(&vps->surf->res, false); + ret = vmw_resource_pin(&vmw_user_object_surface(&vps->uo)->res, false); if (ret) goto out_srf_unref; @@ -1175,30 +1091,47 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, vps->content_fb_type = new_content_type; /* + * The drm fb code will do blit's via the vmap interface, which doesn't + * trigger vmw_bo page dirty tracking due to being kernel side (and thus + * doesn't require mmap'ing) so we have to update the surface's dirty + * regions by hand but we want to be careful to not overwrite the + * resource if it has been written to by the gpu (res_dirty). + */ + if (vps->uo.buffer && vps->uo.buffer->is_dumb) { + struct vmw_surface *surf = vmw_user_object_surface(&vps->uo); + struct vmw_resource *res = &surf->res; + + if (!res->res_dirty && drm_atomic_helper_damage_merged(old_state, + new_state, + &rect)) { + /* + * At some point it might be useful to actually translate + * (rect.x1, rect.y1) => start, and (rect.x2, rect.y2) => end, + * but currently the fb code will just report the entire fb + * dirty so in practice it doesn't matter. + */ + pgoff_t start = res->guest_memory_offset >> PAGE_SHIFT; + pgoff_t end = __KERNEL_DIV_ROUND_UP(res->guest_memory_offset + + res->guest_memory_size, + PAGE_SIZE); + vmw_resource_dirty_update(res, start, end); + } + } + + /* * This should only happen if the buffer object is too large to create a * proxy surface for. - * If we are a 2D VM with a buffer object then we have to use CPU blit - * so cache these mappings */ - if (vps->content_fb_type == SEPARATE_BO && - !(dev_priv->capabilities & SVGA_CAP_3D)) + if (vps->content_fb_type == SEPARATE_BO) vps->cpp = new_fb->pitches[0] / new_fb->width; return 0; out_srf_unref: - vmw_surface_unreference(&vps->surf); + vmw_user_object_unref(&vps->uo); 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) { @@ -1206,68 +1139,6 @@ static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, 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) { @@ -1303,7 +1174,7 @@ vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, 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; + struct vmw_bo *src_bo, *dst_bo; u32 src_offset, dst_offset; s32 src_pitch, dst_pitch; s32 width, height; @@ -1317,11 +1188,11 @@ vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, diff.cpp = stdu->cpp; - dst_bo = &stdu->display_srf->res.backup->base; - dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; + dst_bo = stdu->display_srf->res.guest_memory_bo; + dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; - src_bo = &vfbbo->buffer->base; + src_bo = vfbbo->buffer; src_pitch = update->vfb->base.pitches[0]; src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * stdu->cpp; @@ -1385,24 +1256,12 @@ static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, 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; - } + 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; return vmw_du_helper_plane_update(&bo_update.base); } @@ -1411,14 +1270,8 @@ 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; @@ -1427,14 +1280,8 @@ vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, 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); @@ -1442,47 +1289,6 @@ static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, } 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) { @@ -1496,7 +1302,7 @@ vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, 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.src.sid = vmw_user_object_surface(&vfbs->uo)->res.id; cmd_copy->body.dest.sid = stdu->display_srf->res.id; return sizeof(*cmd_copy); @@ -1565,13 +1371,9 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, 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) { + if (vmw_user_object_surface(&vfbs->uo)->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; @@ -1588,7 +1390,7 @@ 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 + * @state: Only used to get crtc info * * Formally update stdu->display_srf to the new plane, and bind the new * plane STDU. This function is called during the commit phase when @@ -1597,24 +1399,25 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, */ static void vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) + struct drm_atomic_state *state) { - struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); - struct drm_crtc *crtc = plane->state->crtc; + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); + struct drm_crtc *crtc = new_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; /* If case of device error, maintain consistent atomic state */ - if (crtc && plane->state->fb) { + if (crtc && new_state->fb) { struct vmw_framebuffer *vfb = - vmw_framebuffer_to_vfb(plane->state->fb); + vmw_framebuffer_to_vfb(new_state->fb); stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); - stdu->display_srf = vps->surf; + stdu->display_srf = vmw_user_object_surface(&vps->uo); stdu->content_fb_type = vps->content_fb_type; stdu->cpp = vps->cpp; @@ -1651,27 +1454,21 @@ 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; - if (event && fence) { - struct drm_file *file_priv = event->base.file_priv; - - 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); } +static void +vmw_stdu_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vmw_private *vmw = vmw_priv(crtc->dev); + struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); + + if (vmw->vkms_enabled) + vmw_vkms_set_crc_surface(crtc, stdu->display_srf); + vmw_vkms_crtc_atomic_flush(crtc, state); +} static const struct drm_plane_funcs vmw_stdu_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, @@ -1685,7 +1482,7 @@ static const struct drm_plane_funcs vmw_stdu_plane_funcs = { static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = vmw_du_cursor_plane_destroy, + .destroy = vmw_cursor_plane_destroy, .reset = vmw_du_plane_reset, .atomic_duplicate_state = vmw_du_plane_duplicate_state, .atomic_destroy_state = vmw_du_plane_destroy_state, @@ -1697,10 +1494,10 @@ static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { */ static const struct drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = { - .atomic_check = vmw_du_cursor_plane_atomic_check, - .atomic_update = vmw_du_cursor_plane_atomic_update, - .prepare_fb = vmw_du_cursor_plane_prepare_fb, - .cleanup_fb = vmw_du_plane_cleanup_fb, + .atomic_check = vmw_cursor_plane_atomic_check, + .atomic_update = vmw_cursor_plane_atomic_update, + .prepare_fb = vmw_cursor_plane_prepare_fb, + .cleanup_fb = vmw_cursor_plane_cleanup_fb, }; static const struct @@ -1712,12 +1509,11 @@ drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = { }; static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { - .prepare = vmw_stdu_crtc_helper_prepare, .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb, .atomic_check = vmw_du_crtc_atomic_check, .atomic_begin = vmw_du_crtc_atomic_begin, - .atomic_flush = vmw_du_crtc_atomic_flush, - .atomic_enable = vmw_stdu_crtc_atomic_enable, + .atomic_flush = vmw_stdu_crtc_atomic_flush, + .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_stdu_crtc_atomic_disable, }; @@ -1731,18 +1527,20 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { * This function is called once per CRTC, and allocates one Screen Target * display unit to represent that CRTC. Since the SVGA device does not separate * out encoder and connector, they are represented as part of the STDU as well. + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) { struct vmw_screen_target_display_unit *stdu; - struct drm_device *dev = dev_priv->dev; + struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_plane *primary, *cursor; + struct drm_plane *primary; + struct vmw_cursor_plane *cursor; struct drm_crtc *crtc; int ret; - stdu = kzalloc(sizeof(*stdu), GFP_KERNEL); if (!stdu) return -ENOMEM; @@ -1760,8 +1558,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) stdu->base.is_implicit = false; /* Initialize primary plane */ - vmw_du_plane_reset(primary); - ret = drm_universal_plane_init(dev, primary, 0, &vmw_stdu_plane_funcs, vmw_primary_plane_formats, @@ -1776,9 +1572,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) drm_plane_enable_fb_damage_clips(primary); /* Initialize cursor plane */ - vmw_du_plane_reset(cursor); - - ret = drm_universal_plane_init(dev, cursor, + ret = drm_universal_plane_init(dev, &cursor->base, 0, &vmw_stdu_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), @@ -1789,9 +1583,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free; } - drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs); - - vmw_du_connector_reset(connector); + drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(&cursor->base); ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -1801,7 +1594,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); ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); @@ -1820,9 +1612,8 @@ static int vmw_stdu_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, &stdu->base.primary, - &stdu->base.cursor, + ret = drm_crtc_init_with_planes(dev, crtc, primary, + &cursor->base, &vmw_stdu_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); @@ -1839,6 +1630,9 @@ 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); + + vmw_du_init(&stdu->base); + return 0; err_free_unregister: @@ -1890,33 +1684,30 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu) */ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; + struct drm_device *dev = &dev_priv->drm; int i, ret; - /* Do nothing if Screen Target support is turned off */ - if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) + /* Do nothing if there's no support for MOBs */ + if (!dev_priv->has_mob) return -ENOSYS; if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) return -ENOSYS; - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); - if (unlikely(ret != 0)) - return ret; - dev_priv->active_display_unit = vmw_du_screen_target; for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { ret = vmw_stdu_init(dev_priv, i); if (unlikely(ret != 0)) { - DRM_ERROR("Failed to initialize STDU %d", i); + drm_err(&dev_priv->drm, + "Failed to initialize STDU %d", i); return ret; } } - DRM_INFO("Screen Target Display device initialized\n"); + drm_mode_config_reset(dev); return 0; } |
