From f3b3355073ffc2ee717693df587e5d1855ab2d22 Mon Sep 17 00:00:00 2001 From: Charmaine Lee Date: Fri, 12 Feb 2016 08:11:56 +0100 Subject: [PATCH 01/13] drm/vmwgfx: Add DXGenMips support Add support for DXGenMips command. Signed-off-by: Charmaine Lee Reviewed-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 5da5de0cb522..723ba16c6084 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3009,6 +3009,26 @@ out_unref: return ret; } +/** + * vmw_cmd_dx_genmips - Validate an SVGA_3D_CMD_DX_GENMIPS command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDXGenMips body; + } *cmd = container_of(header, typeof(*cmd), header); + + return vmw_view_id_val_add(sw_context, vmw_view_sr, + cmd->body.shaderResourceViewId); +} + static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf, uint32_t *size) @@ -3297,7 +3317,7 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { &vmw_cmd_dx_clear_depthstencil_view, true, false, true), VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid, true, false, true), - VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_invalid, + VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_dx_genmips, true, false, true), VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE, &vmw_cmd_dx_check_subresource, true, false, true), From fea7dd547b038bfed6728641dc35703ab29a16d3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 08:26:37 +0100 Subject: [PATCH 02/13] drm/vmwgfx: Fix a screen object framebuffer dirty corner case If there are no cliprects for a particular crtc, an invalid command would have been generated. If that's the case, instead ditch the generated command sequence. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c5a1a08b0449..cbc1fbaa3d8e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -738,6 +738,11 @@ static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty) SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; int i; + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; cmd->header.size = sizeof(cmd->body) + region_size; @@ -875,6 +880,11 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, */ static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) { + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + vmw_fifo_commit(dirty->dev_priv, sizeof(struct vmw_kms_sou_dmabuf_blit) * dirty->num_hits); @@ -967,6 +977,11 @@ out_revert: */ static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) { + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + vmw_fifo_commit(dirty->dev_priv, sizeof(struct vmw_kms_sou_readback_blit) * dirty->num_hits); From 897b818077f3c11eda82ead57fd173c7f12f9796 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 08:32:08 +0100 Subject: [PATCH 03/13] drm/vmwgfx: Fix screen object page flips for large framebuffers For page flips the framebuffer may be much larger than the crtc scanout area and may be attached to multiple crtcs. When flipping a crtc, make sure we dirty only that crtc's area of the framebuffer. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 5 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 18 +++++++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b221a8c40282..29bec974464c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -663,9 +663,8 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, break; case vmw_du_screen_object: ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, - clips, num_clips, increment, - true, - NULL); + clips, NULL, num_clips, + increment, true, NULL); break; case vmw_du_legacy: ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index edd81503516d..d41928c12a42 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -287,6 +287,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, unsigned num_clips, int increment, bool interruptible, struct vmw_fence_obj **out_fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index cbc1fbaa3d8e..c0de3b8d4e5d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -470,7 +470,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *old_fb = crtc->primary->fb; struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); struct vmw_fence_obj *fence = NULL; - struct drm_clip_rect clips; + struct drm_vmw_rect vclips; int ret; /* require ScreenObject support for page flipping */ @@ -483,17 +483,18 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, crtc->primary->fb = fb; /* do a full screen dirty update */ - clips.x1 = clips.y1 = 0; - clips.x2 = fb->width; - clips.y2 = fb->height; + vclips.x = crtc->x; + vclips.y = crtc->y; + vclips.w = crtc->mode.hdisplay; + vclips.h = crtc->mode.vdisplay; if (vfb->dmabuf) ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, - &clips, 1, 1, + NULL, &vclips, 1, 1, true, &fence); else ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, - &clips, NULL, NULL, + NULL, &vclips, NULL, 0, 0, 1, 1, &fence); @@ -919,6 +920,8 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) * @dev_priv: Pointer to the device private structure. * @framebuffer: Pointer to the dma-buffer backed framebuffer. * @clips: Array of clip rects. + * @vclips: Alternate array of clip rects. Either @clips or @vclips must + * be NULL. * @num_clips: Number of clip rects in @clips. * @increment: Increment to use when looping over @clips. * @interruptible: Whether to perform waits interruptible if possible. @@ -932,6 +935,7 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, unsigned num_clips, int increment, bool interruptible, struct vmw_fence_obj **out_fence) @@ -955,7 +959,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, dirty.clip = vmw_sou_dmabuf_clip; dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * num_clips; - ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, NULL, + ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 0, 0, num_clips, increment, &dirty); vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL); From b1097aeb6f23433c4e073a8d7447a8d919e1e163 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 08:54:07 +0100 Subject: [PATCH 04/13] drm/vmwgfx: Rework screen target page flips v2 Gnome-Shell / Wayland assumes that page-flips can be done on a crtc regardless of framebuffer size and the crtc position within the framebuffer. Therefore rework the screen target code to correctly handle changes in framebuffer size and content_fb_type. Also make sure that we update the screen target correctly when the content_fb_type is not SAME_AS_DISPLAY. This commit breaks out the framebuffer binding code from crtc_set so it can be used both from page_flip() and crtc_set() and reworks those functions a bit to be more robust. v2: Address review comments by Sinclair Yeh. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 426 ++++++++++++--------------- 1 file changed, 190 insertions(+), 236 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 4ef5ffd7189d..c93af718a740 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -96,7 +96,6 @@ struct vmw_stdu_surface_copy { * 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_fb: holds the rendered content, can be a surface or DMA buffer * @content_type: content_fb type * @defined: true if the current display unit has been initialized */ @@ -104,8 +103,6 @@ struct vmw_screen_target_display_unit { struct vmw_display_unit base; struct vmw_surface *display_srf; - struct drm_framebuffer *content_fb; - enum stdu_content_type content_fb_type; bool defined; @@ -121,22 +118,6 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); * Screen Target Display Unit helper Functions *****************************************************************************/ -/** - * vmw_stdu_pin_display - pins the resource associated with the display surface - * - * @stdu: contains the display surface - * - * Since the display surface can either be a private surface allocated by us, - * or it can point to the content surface, we use this function to not pin the - * same resource twice. - */ -static int vmw_stdu_pin_display(struct vmw_screen_target_display_unit *stdu) -{ - return vmw_resource_pin(&stdu->display_srf->res, false); -} - - - /** * vmw_stdu_unpin_display - unpins the resource associated with display surface * @@ -153,13 +134,7 @@ static void vmw_stdu_unpin_display(struct vmw_screen_target_display_unit *stdu) struct vmw_resource *res = &stdu->display_srf->res; vmw_resource_unpin(res); - - if (stdu->content_fb_type != SAME_AS_DISPLAY) { - vmw_resource_unreference(&res); - stdu->content_fb_type = SAME_AS_DISPLAY; - } - - stdu->display_srf = NULL; + vmw_surface_unreference(&stdu->display_srf); } } @@ -185,6 +160,9 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) * * @dev_priv: VMW DRM device * @stdu: display unit to create a Screen Target for + * @mode: The mode to set. + * @crtc_x: X coordinate of screen target relative to framebuffer origin. + * @crtc_y: Y coordinate of screen target relative to framebuffer origin. * * Creates a STDU that we can used later. This function is called whenever the * framebuffer size changes. @@ -193,7 +171,9 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) * 0 on success, error code on failure */ static int vmw_stdu_define_st(struct vmw_private *dev_priv, - struct vmw_screen_target_display_unit *stdu) + struct vmw_screen_target_display_unit *stdu, + struct drm_display_mode *mode, + int crtc_x, int crtc_y) { struct { SVGA3dCmdHeader header; @@ -211,14 +191,14 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, cmd->header.size = sizeof(cmd->body); cmd->body.stid = stdu->base.unit; - cmd->body.width = stdu->display_srf->base_size.width; - cmd->body.height = stdu->display_srf->base_size.height; + cmd->body.width = mode->hdisplay; + cmd->body.height = mode->vdisplay; cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; cmd->body.dpi = 0; - cmd->body.xRoot = stdu->base.crtc.x; - cmd->body.yRoot = stdu->base.crtc.y; - - if (!stdu->base.is_implicit) { + if (stdu->base.is_implicit) { + cmd->body.xRoot = crtc_x; + cmd->body.yRoot = crtc_y; + } else { cmd->body.xRoot = stdu->base.gui_x; cmd->body.yRoot = stdu->base.gui_y; } @@ -392,7 +372,128 @@ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, return ret; } +/** + * vmw_stdu_bind_fb - Bind an fb to a defined screen target + * + * @dev_priv: Pointer to a device private struct. + * @crtc: The crtc holding the screen target. + * @mode: The mode currently used by the screen target. Must be non-NULL. + * @new_fb: The new framebuffer to bind. Must be non-NULL. + * + * RETURNS: + * 0 on success, error code on failure. + */ +static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, + struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_framebuffer *new_fb) +{ + struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); + struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); + struct vmw_surface *new_display_srf = NULL; + enum stdu_content_type new_content_type; + struct vmw_framebuffer_surface *new_vfbs; + int ret; + WARN_ON_ONCE(!stdu->defined); + + if (!vfb->dmabuf && new_fb->width == mode->hdisplay && + new_fb->height == mode->vdisplay) + new_content_type = SAME_AS_DISPLAY; + else if (vfb->dmabuf) + new_content_type = SEPARATE_DMA; + else + new_content_type = SEPARATE_SURFACE; + + if (new_content_type != SAME_AS_DISPLAY && + !stdu->display_srf) { + struct vmw_surface content_srf; + struct drm_vmw_size display_base_size = {0}; + + display_base_size.width = mode->hdisplay; + display_base_size.height = mode->vdisplay; + display_base_size.depth = 1; + + /* + * If content buffer is a DMA buf, then we have to construct + * surface info + */ + if (new_content_type == SEPARATE_DMA) { + + switch (new_fb->bits_per_pixel) { + case 32: + content_srf.format = SVGA3D_X8R8G8B8; + break; + + case 16: + content_srf.format = SVGA3D_R5G6B5; + break; + + case 8: + content_srf.format = SVGA3D_P8; + break; + + default: + DRM_ERROR("Invalid format\n"); + return -EINVAL; + } + + content_srf.flags = 0; + content_srf.mip_levels[0] = 1; + content_srf.multisample_count = 0; + } else { + new_vfbs = vmw_framebuffer_to_vfbs(new_fb); + content_srf = *new_vfbs->surface; + } + + + ret = vmw_surface_gb_priv_define(crtc->dev, + 0, /* because kernel visible only */ + content_srf.flags, + content_srf.format, + true, /* a scanout buffer */ + content_srf.mip_levels[0], + content_srf.multisample_count, + 0, + display_base_size, + &new_display_srf); + if (unlikely(ret != 0)) { + DRM_ERROR("Could not allocate screen target surface.\n"); + return ret; + } + } else if (new_content_type == SAME_AS_DISPLAY) { + new_vfbs = vmw_framebuffer_to_vfbs(new_fb); + new_display_srf = vmw_surface_reference(new_vfbs->surface); + } + + if (new_display_srf) { + /* Pin new surface before flipping */ + ret = vmw_resource_pin(&new_display_srf->res, false); + if (ret) + goto out_srf_unref; + + ret = vmw_stdu_bind_st(dev_priv, stdu, &new_display_srf->res); + if (ret) + goto out_srf_unpin; + + /* Unpin and unreference old surface */ + vmw_stdu_unpin_display(stdu); + + /* Transfer the reference */ + stdu->display_srf = new_display_srf; + new_display_srf = NULL; + } + + crtc->primary->fb = new_fb; + stdu->content_fb_type = new_content_type; + return 0; + +out_srf_unpin: + vmw_resource_unpin(&new_display_srf->res); +out_srf_unref: + vmw_surface_unreference(&new_display_srf); + return ret; +} /** * vmw_stdu_crtc_set_config - Sets a mode @@ -410,13 +511,12 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) { struct vmw_private *dev_priv; struct vmw_screen_target_display_unit *stdu; - struct vmw_framebuffer *vfb; - struct vmw_framebuffer_surface *new_vfbs; struct drm_display_mode *mode; struct drm_framebuffer *new_fb; struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; + bool turning_off; int ret; @@ -424,13 +524,11 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) return -EINVAL; crtc = set->crtc; - crtc->x = set->x; - crtc->y = set->y; stdu = vmw_crtc_to_stdu(crtc); mode = set->mode; new_fb = set->fb; dev_priv = vmw_priv(crtc->dev); - + turning_off = set->num_connectors == 0 || !mode || !new_fb; if (set->num_connectors > 1) { DRM_ERROR("Too many connectors\n"); @@ -444,146 +542,40 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) return -EINVAL; } + if (!turning_off && (set->x + mode->hdisplay > new_fb->width || + set->y + mode->vdisplay > new_fb->height)) { + DRM_ERROR("Set outside of framebuffer\n"); + return -EINVAL; + } /* Since they always map one to one these are safe */ connector = &stdu->base.connector; encoder = &stdu->base.encoder; - - /* - * After this point the CRTC will be considered off unless a new fb - * is bound - */ if (stdu->defined) { - /* Unbind current surface by binding an invalid one */ ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); - if (unlikely(ret != 0)) + if (ret) return ret; - /* Update Screen Target, display will now be blank */ - if (crtc->primary->fb) { - vmw_stdu_update_st(dev_priv, stdu); - if (unlikely(ret != 0)) - return ret; - } - - crtc->primary->fb = NULL; - crtc->enabled = false; - encoder->crtc = NULL; - connector->encoder = NULL; - vmw_stdu_unpin_display(stdu); - stdu->content_fb = NULL; - stdu->content_fb_type = SAME_AS_DISPLAY; + (void) vmw_stdu_update_st(dev_priv, stdu); ret = vmw_stdu_destroy_st(dev_priv, stdu); - /* The hardware is hung, give up */ - if (unlikely(ret != 0)) + if (ret) return ret; + + crtc->primary->fb = NULL; + crtc->enabled = false; + encoder->crtc = NULL; + connector->encoder = NULL; + stdu->content_fb_type = SAME_AS_DISPLAY; + crtc->x = set->x; + crtc->y = set->y; } - - /* Any of these conditions means the caller wants CRTC off */ - if (set->num_connectors == 0 || !mode || !new_fb) + if (turning_off) return 0; - - if (set->x + mode->hdisplay > new_fb->width || - set->y + mode->vdisplay > new_fb->height) { - DRM_ERROR("Set outside of framebuffer\n"); - return -EINVAL; - } - - stdu->content_fb = new_fb; - vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - - if (vfb->dmabuf) - stdu->content_fb_type = SEPARATE_DMA; - - /* - * If the requested mode is different than the width and height - * of the FB or if the content buffer is a DMA buf, then allocate - * a display FB that matches the dimension of the mode - */ - if (mode->hdisplay != new_fb->width || - mode->vdisplay != new_fb->height || - stdu->content_fb_type != SAME_AS_DISPLAY) { - struct vmw_surface content_srf; - struct drm_vmw_size display_base_size = {0}; - struct vmw_surface *display_srf; - - - display_base_size.width = mode->hdisplay; - display_base_size.height = mode->vdisplay; - display_base_size.depth = 1; - - /* - * If content buffer is a DMA buf, then we have to construct - * surface info - */ - if (stdu->content_fb_type == SEPARATE_DMA) { - - switch (new_fb->bits_per_pixel) { - case 32: - content_srf.format = SVGA3D_X8R8G8B8; - break; - - case 16: - content_srf.format = SVGA3D_R5G6B5; - break; - - case 8: - content_srf.format = SVGA3D_P8; - break; - - default: - DRM_ERROR("Invalid format\n"); - ret = -EINVAL; - goto err_unref_content; - } - - content_srf.flags = 0; - content_srf.mip_levels[0] = 1; - content_srf.multisample_count = 0; - } else { - - stdu->content_fb_type = SEPARATE_SURFACE; - - new_vfbs = vmw_framebuffer_to_vfbs(new_fb); - content_srf = *new_vfbs->surface; - } - - - ret = vmw_surface_gb_priv_define(crtc->dev, - 0, /* because kernel visible only */ - content_srf.flags, - content_srf.format, - true, /* a scanout buffer */ - content_srf.mip_levels[0], - content_srf.multisample_count, - 0, - display_base_size, - &display_srf); - if (unlikely(ret != 0)) { - DRM_ERROR("Cannot allocate a display FB.\n"); - goto err_unref_content; - } - - stdu->display_srf = display_srf; - } else { - new_vfbs = vmw_framebuffer_to_vfbs(new_fb); - stdu->display_srf = new_vfbs->surface; - } - - - ret = vmw_stdu_pin_display(stdu); - if (unlikely(ret != 0)) { - stdu->display_srf = NULL; - goto err_unref_content; - } - - vmw_svga_enable(dev_priv); - /* * Steps to displaying a surface, assume surface is already * bound: @@ -592,35 +584,32 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) * 3. update that screen target (this is done later by * vmw_kms_stdu_do_surface_dirty_or_present) */ - ret = vmw_stdu_define_st(dev_priv, stdu); - if (unlikely(ret != 0)) - goto err_unpin_display_and_content; + /* + * Note on error handling: We can't really restore the crtc to + * it's original state on error, but we at least update the + * current state to what's submitted to hardware to enable + * future recovery. + */ + vmw_svga_enable(dev_priv); + ret = vmw_stdu_define_st(dev_priv, stdu, mode, set->x, set->y); + if (ret) + return ret; - ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); - if (unlikely(ret != 0)) - goto err_unpin_destroy_st; + crtc->x = set->x; + crtc->y = set->y; + crtc->mode = *mode; + ret = vmw_stdu_bind_fb(dev_priv, crtc, mode, new_fb); + if (ret) + return ret; + crtc->enabled = true; connector->encoder = encoder; encoder->crtc = crtc; - crtc->mode = *mode; - crtc->primary->fb = new_fb; - crtc->enabled = true; - - return ret; - -err_unpin_destroy_st: - vmw_stdu_destroy_st(dev_priv, stdu); -err_unpin_display_and_content: - vmw_stdu_unpin_display(stdu); -err_unref_content: - stdu->content_fb = NULL; - return ret; + return 0; } - - /** * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target * @@ -648,59 +637,31 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_screen_target_display_unit *stdu; + struct drm_vmw_rect vclips; + struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); int ret; - if (crtc == NULL) - return -EINVAL; - dev_priv = vmw_priv(crtc->dev); stdu = vmw_crtc_to_stdu(crtc); - crtc->primary->fb = new_fb; - stdu->content_fb = new_fb; - if (stdu->display_srf) { - /* - * If the display surface is the same as the content surface - * then remove the reference - */ - if (stdu->content_fb_type == SAME_AS_DISPLAY) { - if (stdu->defined) { - /* Unbind the current surface */ - ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); - if (unlikely(ret != 0)) - goto err_out; - } - vmw_stdu_unpin_display(stdu); - stdu->display_srf = NULL; - } - } + if (!stdu->defined) + return -EINVAL; + ret = vmw_stdu_bind_fb(dev_priv, crtc, &crtc->mode, new_fb); + if (ret) + return ret; - if (!new_fb) { - /* Blanks the display */ - (void) vmw_stdu_update_st(dev_priv, stdu); - - return 0; - } - - - if (stdu->content_fb_type == SAME_AS_DISPLAY) { - stdu->display_srf = vmw_framebuffer_to_vfbs(new_fb)->surface; - ret = vmw_stdu_pin_display(stdu); - if (ret) { - stdu->display_srf = NULL; - goto err_out; - } - - /* Bind display surface */ - ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); - if (unlikely(ret != 0)) - goto err_unpin_display_and_content; - } - - /* Update display surface: after this point everything is bound */ - ret = vmw_stdu_update_st(dev_priv, stdu); - if (unlikely(ret != 0)) + vclips.x = crtc->x; + vclips.y = crtc->y; + vclips.w = crtc->mode.hdisplay; + vclips.h = crtc->mode.vdisplay; + if (vfb->dmabuf) + ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, + 1, 1, true, false); + else + ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips, + NULL, 0, 0, 1, 1, NULL); + if (ret) return ret; if (event) { @@ -721,14 +682,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, vmw_fifo_flush(dev_priv, false); } - return ret; - -err_unpin_display_and_content: - vmw_stdu_unpin_display(stdu); -err_out: - crtc->primary->fb = NULL; - stdu->content_fb = NULL; - return ret; + return 0; } From 75c0685549bb4af6e66bcc1c4c055add531b3880 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:00:26 +0100 Subject: [PATCH 05/13] drm/vmwgfx: Break out implicit fb code Preparation for supporting explicit fbs for screen objects and screen targets. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 92 ++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 12 +++ drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 125 +++------------------------ 4 files changed, 120 insertions(+), 112 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5cb1b1687cd4..b92521d70efc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -407,8 +407,9 @@ struct vmw_private { void *fb_info; enum vmw_display_unit_type active_display_unit; struct vmw_legacy_display *ldu_priv; - struct vmw_screen_object_display *sou_priv; struct vmw_overlay *overlay_priv; + unsigned num_implicit; + struct vmw_framebuffer *implicit_fb; /* * Context and surface management. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 29bec974464c..26c2e9edb2b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2095,3 +2095,95 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, return 0; } + +/** + * 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) +{ + lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); + + if (du->active_implicit) { + if (--(dev_priv->num_implicit) == 0) + dev_priv->implicit_fb = NULL; + du->active_implicit = false; + } +} + +/** + * 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) +{ + lockdep_assert_held_once(&dev_priv->dev->mode_config.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++; + } +} + +/** + * 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); + + lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); + + if (!du->is_implicit) + return true; + + if (dev_priv->num_implicit != 1) + return false; + + return true; +} + +/** + * 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 vmw_framebuffer *vfb; + + lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); + + if (!du->is_implicit) + return; + + vfb = vmw_framebuffer_to_vfb(crtc->primary->fb); + WARN_ON_ONCE(dev_priv->num_implicit != 1 && + dev_priv->implicit_fb != vfb); + + dev_priv->implicit_fb = vfb; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index d41928c12a42..0b5c9ab4a2f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -178,6 +178,7 @@ struct vmw_display_unit { int gui_x; int gui_y; bool is_implicit; + bool active_implicit; }; #define vmw_crtc_to_du(x) \ @@ -254,6 +255,17 @@ 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); + + /* * Legacy display unit functions - vmwgfx_ldu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c0de3b8d4e5d..c11b196bf35f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -74,19 +74,6 @@ struct vmw_kms_sou_dirty_cmd { SVGA3dCmdBlitSurfaceToScreen body; }; - -/* - * Other structs. - */ - -struct vmw_screen_object_display { - unsigned num_implicit; - - struct vmw_framebuffer *implicit_fb; - SVGAFifoCmdDefineGMRFB cur; - struct vmw_dma_buffer *pinned_gmrfb; -}; - /** * Display unit using screen objects. */ @@ -97,7 +84,6 @@ struct vmw_screen_object_unit { struct vmw_dma_buffer *buffer; /**< Backing store buffer */ bool defined; - bool active_implicit; }; static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) @@ -116,33 +102,6 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) vmw_sou_destroy(vmw_crtc_to_sou(crtc)); } -static void vmw_sou_del_active(struct vmw_private *vmw_priv, - struct vmw_screen_object_unit *sou) -{ - struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - - if (sou->active_implicit) { - if (--(ld->num_implicit) == 0) - ld->implicit_fb = NULL; - sou->active_implicit = false; - } -} - -static void vmw_sou_add_active(struct vmw_private *vmw_priv, - struct vmw_screen_object_unit *sou, - struct vmw_framebuffer *vfb) -{ - struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - - BUG_ON(!ld->num_implicit && ld->implicit_fb); - - if (!sou->active_implicit && sou->base.is_implicit) { - ld->implicit_fb = vfb; - sou->active_implicit = true; - ld->num_implicit++; - } -} - /** * Send the fifo command to create a screen. */ @@ -323,13 +282,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) return -EINVAL; } - /* sou only supports one fb active at the time */ + /* Only one active implicit frame-buffer at a time. */ if (sou->base.is_implicit && - dev_priv->sou_priv->implicit_fb && vfb && - !(dev_priv->sou_priv->num_implicit == 1 && - sou->active_implicit) && - dev_priv->sou_priv->implicit_fb != vfb) { - DRM_ERROR("Multiple framebuffers not supported\n"); + dev_priv->implicit_fb && vfb && + !(dev_priv->num_implicit == 1 && + sou->base.active_implicit) && + dev_priv->implicit_fb != vfb) { + DRM_ERROR("Multiple implicit framebuffers not supported.\n"); return -EINVAL; } @@ -351,7 +310,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) crtc->y = 0; crtc->enabled = false; - vmw_sou_del_active(dev_priv, sou); + vmw_kms_del_active(dev_priv, &sou->base); vmw_sou_backing_free(dev_priv, sou); @@ -415,7 +374,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) return ret; } - vmw_sou_add_active(dev_priv, sou, vfb); + vmw_kms_add_active(dev_priv, &sou->base, vfb); connector->encoder = encoder; encoder->crtc = crtc; @@ -428,39 +387,6 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) return 0; } -/** - * Returns if this unit can be page flipped. - * Must be called with the mode_config mutex held. - */ -static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv, - struct drm_crtc *crtc) -{ - struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); - - if (!sou->base.is_implicit) - return true; - - if (dev_priv->sou_priv->num_implicit != 1) - return false; - - return true; -} - -/** - * Update the implicit fb to the current fb of this crtc. - * Must be called with the mode_config mutex held. - */ -static void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc) -{ - struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); - - BUG_ON(!sou->base.is_implicit); - - dev_priv->sou_priv->implicit_fb = - vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); -} - static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, @@ -473,11 +399,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_vmw_rect vclips; int ret; - /* require ScreenObject support for page flipping */ - if (!dev_priv->sou_priv) - return -ENOSYS; - - if (!vmw_sou_screen_object_flippable(dev_priv, crtc)) + if (!vmw_kms_crtc_flippable(dev_priv, crtc)) return -EINVAL; crtc->primary->fb = fb; @@ -522,7 +444,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, vmw_fence_obj_unreference(&fence); if (vmw_crtc_to_du(crtc)->is_implicit) - vmw_sou_update_implicit_fb(dev_priv, crtc); + vmw_kms_update_implicit_fb(dev_priv, crtc); return ret; @@ -587,8 +509,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) encoder = &sou->base.encoder; connector = &sou->base.connector; - sou->active_implicit = false; - + 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; @@ -623,11 +544,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) struct drm_device *dev = dev_priv->dev; int i, ret; - if (dev_priv->sou_priv) { - DRM_INFO("sou system already on\n"); - return -EINVAL; - } - if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { DRM_INFO("Not using screen objects," " missing cap SCREEN_OBJECT_2\n"); @@ -635,16 +551,12 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) } ret = -ENOMEM; - dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL); - if (unlikely(!dev_priv->sou_priv)) - goto err_no_mem; - - dev_priv->sou_priv->num_implicit = 0; - dev_priv->sou_priv->implicit_fb = NULL; + dev_priv->num_implicit = 0; + dev_priv->implicit_fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); if (unlikely(ret != 0)) - goto err_free; + return ret; ret = drm_mode_create_dirty_info_property(dev); if (unlikely(ret != 0)) @@ -661,10 +573,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) err_vblank_cleanup: drm_vblank_cleanup(dev); -err_free: - kfree(dev_priv->sou_priv); - dev_priv->sou_priv = NULL; -err_no_mem: return ret; } @@ -672,13 +580,8 @@ int vmw_kms_sou_close_display(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - if (!dev_priv->sou_priv) - return -ENOSYS; - drm_vblank_cleanup(dev); - kfree(dev_priv->sou_priv); - return 0; } From 4d492a07ad62e58c47d863266ff347a9f202016b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:01:29 +0100 Subject: [PATCH 06/13] drm/vmwgfx: Add implicit framebuffer checks to the screen target code Just like for screen objects, make sure we use only a single framebuffer for implicit placement. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index c93af718a740..a5ab826879d1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -510,6 +510,7 @@ out_srf_unref: static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) { struct vmw_private *dev_priv; + struct vmw_framebuffer *vfb; struct vmw_screen_target_display_unit *stdu; struct drm_display_mode *mode; struct drm_framebuffer *new_fb; @@ -529,6 +530,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) new_fb = set->fb; dev_priv = vmw_priv(crtc->dev); turning_off = set->num_connectors == 0 || !mode || !new_fb; + vfb = (new_fb) ? vmw_framebuffer_to_vfb(new_fb) : NULL; if (set->num_connectors > 1) { DRM_ERROR("Too many connectors\n"); @@ -548,6 +550,14 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) return -EINVAL; } + /* Only one active implicit frame-buffer at a time. */ + if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb && + !(dev_priv->num_implicit == 1 && stdu->base.active_implicit) + && dev_priv->implicit_fb != vfb) { + DRM_ERROR("Multiple implicit framebuffers not supported.\n"); + return -EINVAL; + } + /* Since they always map one to one these are safe */ connector = &stdu->base.connector; encoder = &stdu->base.encoder; @@ -559,6 +569,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) vmw_stdu_unpin_display(stdu); (void) vmw_stdu_update_st(dev_priv, stdu); + vmw_kms_del_active(dev_priv, &stdu->base); ret = vmw_stdu_destroy_st(dev_priv, stdu); if (ret) @@ -603,6 +614,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) if (ret) return ret; + vmw_kms_add_active(dev_priv, &stdu->base, vfb); crtc->enabled = true; connector->encoder = encoder; encoder->crtc = crtc; @@ -644,13 +656,16 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, dev_priv = vmw_priv(crtc->dev); stdu = vmw_crtc_to_stdu(crtc); - if (!stdu->defined) + if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) return -EINVAL; ret = vmw_stdu_bind_fb(dev_priv, crtc, &crtc->mode, new_fb); if (ret) return ret; + if (stdu->base.is_implicit) + vmw_kms_update_implicit_fb(dev_priv, crtc); + vclips.x = crtc->x; vclips.y = crtc->y; vclips.w = crtc->mode.hdisplay; From 578e609a096e086dc1259611cfb47b1499bcded6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:45:42 +0100 Subject: [PATCH 07/13] drm/vmwgfx: Add suggested screen x and y connector properties Introduced by qxl, add these properties as a generic way to tell a display manager about the GUI layout. Also add the hotplug_mode_update_property which advises display managers to reread the mode list on a hotplug event. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 32 ++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 10 +++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 10 +++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 6 ++++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index b92521d70efc..13970fe6bb86 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -408,6 +408,7 @@ struct vmw_private { enum vmw_display_unit_type active_display_unit; struct vmw_legacy_display *ldu_priv; struct vmw_overlay *overlay_priv; + struct drm_property *hotplug_mode_update_property; unsigned num_implicit; struct vmw_framebuffer *implicit_fb; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 26c2e9edb2b6..6726294dfccb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1108,6 +1108,22 @@ int vmw_kms_present(struct vmw_private *dev_priv, return 0; } +static void +vmw_kms_create_hotplug_mode_update_property(struct vmw_private *dev_priv) +{ + if (dev_priv->hotplug_mode_update_property) + return; + + dev_priv->hotplug_mode_update_property = + drm_property_create_range(dev_priv->dev, + DRM_MODE_PROP_IMMUTABLE, + "hotplug_mode_update", 0, 1); + + if (!dev_priv->hotplug_mode_update_property) + return; + +} + int vmw_kms_init(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -1120,6 +1136,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.max_width = dev_priv->texture_max_width; dev->mode_config.max_height = dev_priv->texture_max_height; + drm_mode_create_suggested_offset_properties(dev); + vmw_kms_create_hotplug_mode_update_property(dev_priv); + ret = vmw_kms_stdu_init_display(dev_priv); if (ret) { ret = vmw_kms_sou_init_display(dev_priv); @@ -1359,15 +1378,28 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, du->pref_active = true; du->gui_x = rects[du->unit].x; du->gui_y = rects[du->unit].y; + drm_object_property_set_value + (&con->base, dev->mode_config.suggested_x_property, + du->gui_x); + drm_object_property_set_value + (&con->base, dev->mode_config.suggested_y_property, + du->gui_y); } else { du->pref_width = 800; du->pref_height = 600; du->pref_active = false; + drm_object_property_set_value + (&con->base, dev->mode_config.suggested_x_property, + 0); + drm_object_property_set_value + (&con->base, dev->mode_config.suggested_y_property, + 0); } con->status = vmw_du_connector_detect(con, true); } mutex_unlock(&dev->mode_config.mutex); + drm_sysfs_hotplug_event(dev); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b6fa44fe8929..8fb17b8f6a8c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -375,8 +375,14 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); + dev->mode_config.dirty_info_property, + 1); + drm_object_attach_property(&connector->base, + dev_priv->hotplug_mode_update_property, 1); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_x_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_y_property, 0); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c11b196bf35f..1390cfface25 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -533,8 +533,14 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, - dev->mode_config.dirty_info_property, - 1); + dev->mode_config.dirty_info_property, + 1); + drm_object_attach_property(&connector->base, + dev_priv->hotplug_mode_update_property, 1); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_x_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_y_property, 0); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index a5ab826879d1..f02bb702c282 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1128,6 +1128,12 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) drm_object_attach_property(&connector->base, dev->mode_config.dirty_info_property, 1); + drm_object_attach_property(&connector->base, + dev_priv->hotplug_mode_update_property, 1); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_x_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.suggested_y_property, 0); return 0; } From 76404ac0a2c358dd63b8ed32e4df69f3b781b7eb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:55:45 +0100 Subject: [PATCH 08/13] drm/vmwgfx: Add connector properties to switch between explicit and implicit placement Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 30 ++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 7 +++++++ drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 7 +++++++ drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 8 +++++++- 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 13970fe6bb86..98cf4ff455ca 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -409,6 +409,7 @@ struct vmw_private { struct vmw_legacy_display *ldu_priv; 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; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6726294dfccb..0e2340fbed17 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1622,6 +1622,12 @@ 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; } @@ -2219,3 +2225,27 @@ void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, dev_priv->implicit_fb = vfb; } + +/** + * 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) +{ + 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, + "implicit_placement", 0, 1); + +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 0b5c9ab4a2f8..aa21aff9870d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -264,7 +264,8 @@ 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); /* diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 8fb17b8f6a8c..13b104709912 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -383,6 +383,11 @@ static int vmw_ldu_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, + 1); return 0; } @@ -418,6 +423,8 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) if (ret != 0) goto err_vblank_cleanup; + vmw_kms_create_implicit_placement_property(dev_priv, true); + if (dev_priv->capabilities & SVGA_CAP_MULTIMON) for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) vmw_ldu_init(dev_priv, i); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 1390cfface25..7ca13ec1291e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -541,6 +541,11 @@ 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; } @@ -568,6 +573,8 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) if (unlikely(ret != 0)) goto err_vblank_cleanup; + 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 f02bb702c282..1cd88d197840 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1134,7 +1134,11 @@ 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; } @@ -1199,6 +1203,8 @@ 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); From 6dd687b42fff7aa681978e117cf3051de0d023a5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:57:15 +0100 Subject: [PATCH 09/13] drm/vmwgfx: Calculate the cursor position based on the crtc gui origin Base the cursor position on the coordinate of the crtc origin in the gui coordinate system rather than in the framebuffer coordinate system. With explicit placement, these may differ (for example when two crtcs scan out of the same framebuffer location). Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 ++ 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, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0e2340fbed17..4742ec4ead27 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -236,8 +236,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) struct vmw_display_unit *du = vmw_crtc_to_du(crtc); bool shown = du->cursor_surface || du->cursor_dmabuf ? true : false; - du->cursor_x = x + crtc->x; - du->cursor_y = y + crtc->y; + du->cursor_x = x + du->set_gui_x; + du->cursor_y = y + du->set_gui_y; /* * FIXME: Unclear whether there's any global state touched by the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index aa21aff9870d..57203212c501 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -179,6 +179,8 @@ struct vmw_display_unit { int gui_y; bool is_implicit; bool active_implicit; + int set_gui_x; + int set_gui_y; }; #define vmw_crtc_to_du(x) \ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 13b104709912..63ccd9871ec9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -288,6 +288,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) crtc->y = set->y; crtc->mode = *mode; crtc->enabled = true; + ldu->base.set_gui_x = set->x; + ldu->base.set_gui_y = set->y; vmw_ldu_add_active(dev_priv, ldu, vfb); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 7ca13ec1291e..8a3d3c9f2d9f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -144,6 +144,8 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, cmd->obj.root.x = sou->base.gui_x; cmd->obj.root.y = sou->base.gui_y; } + sou->base.set_gui_x = cmd->obj.root.x; + sou->base.set_gui_y = cmd->obj.root.y; /* Ok to assume that buffer is pinned in vram */ vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 1cd88d197840..fe42a2cefb86 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -202,6 +202,8 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, cmd->body.xRoot = stdu->base.gui_x; cmd->body.yRoot = stdu->base.gui_y; } + stdu->base.set_gui_x = cmd->body.xRoot; + stdu->base.set_gui_y = cmd->body.yRoot; vmw_fifo_commit(dev_priv, sizeof(*cmd)); From 2e69b25bb12cfd32250684b600652589d823a96c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 09:59:50 +0100 Subject: [PATCH 10/13] drm/vmwgfx: Default to explicit crtc placement for screen targets and screen objects Enables using multiple framebuffers. For legacy display units, explicit crtc placement is not supported due to hardware limitations. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 8a3d3c9f2d9f..0ea22fd112c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -516,7 +516,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) sou->base.pref_width = dev_priv->initial_width; sou->base.pref_height = dev_priv->initial_height; sou->base.pref_mode = NULL; - sou->base.is_implicit = true; + sou->base.is_implicit = false; drm_connector_init(dev, connector, &vmw_sou_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index fe42a2cefb86..b949102ad864 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1109,7 +1109,7 @@ 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; - stdu->base.is_implicit = true; + stdu->base.is_implicit = false; drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); From 5ea1734827bb49a738c9d8bda783763d729bf233 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 10:01:28 +0100 Subject: [PATCH 11/13] drm/vmwgfx: Send a hotplug event at master_set Make sure drm clients (mostly the X server) are communicated the current layout when switched in. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0ee76e523a90..1ca90377581c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1204,6 +1204,7 @@ static int vmw_master_set(struct drm_device *dev, } dev_priv->active_master = vmaster; + drm_sysfs_hotplug_event(dev); return 0; } From b0dc6d43ed89b861b8ee32cc454d2d0c89074843 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2016 10:34:19 +0100 Subject: [PATCH 12/13] drm/vmwgfx: Allow the UPDATE_LAYOUT ioctl from control nodes On vmware there is a daemon telling the KMS system about the GUI layout. Typically it talks to the X server but in the absence of an X server or if there are multiple, it wants to talk directly to the vmwgfx kernel module. Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1ca90377581c..6cbb7d4bdd11 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -195,7 +195,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_MASTER | DRM_AUTH), VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, - DRM_MASTER), + DRM_MASTER | DRM_CONTROL_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_SHADER, vmw_shader_define_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), From 5476aa46ff0377229f780c42e77b7e7e756040c7 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 14 Mar 2016 14:41:08 +0100 Subject: [PATCH 13/13] drm/vmwgfx: Bump driver minor signals availability of resolutionKMS support Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclar Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 98cf4ff455ca..019a6ca3e8e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,9 +40,9 @@ #include #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20150810" +#define VMWGFX_DRIVER_DATE "20160210" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 9 +#define VMWGFX_DRIVER_MINOR 10 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)