All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3]: Large topology fix
@ 2017-08-21 20:10 Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 1/3] drm/vmwgfx: Support topology greater than texture size Sinclair Yeh
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Sinclair Yeh @ 2017-08-21 20:10 UTC (permalink / raw)
  To: stable

This series fixes a regression that prevented our customers from
spanning two 4K monitors.

Patch 1/3 is > 100 lines and is required for the subsequent 2 patches.

Even though I have worked with the distros separately on these patches
already, I figured I'd give stable-kernel a try and see if it is
possible to get them accepted.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] drm/vmwgfx: Support topology greater than texture size
  2017-08-21 20:10 [PATCH 0/3]: Large topology fix Sinclair Yeh
@ 2017-08-21 20:10 ` Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 2/3] drm/vmwgfx: Fix large topology crash Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 3/3] drm/vmwgfx: Limit max desktop dimensions to 8Kx8K Sinclair Yeh
  2 siblings, 0 replies; 4+ messages in thread
From: Sinclair Yeh @ 2017-08-21 20:10 UTC (permalink / raw)
  To: stable; +Cc: Sinclair Yeh

Most of the display servers today use a single surface to represent the
entire desktop even if it's stretched across multiple screens.

For vmwgfx with STDU, the maximum surface size is limited to the
maximum texture size on the host.  On a 2D VM, this limits our
ability to support configurations with more than one 4K monitor.

To get past this limitation, we will now allow using a large DMA buf
as the framebuffer, and take care of blitting contents from this DMA buf
to the display buffer.

backported Commit 810b3e1683d0 upstream.
Cc: <stable@vger.kernel.org> # 4.11.x

Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c  |  30 ++++-
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 209 ++++++++++++++++++++++++++++++++++-
 2 files changed, 237 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index d492d57..e25df21 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -885,6 +885,24 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
 }
 
 /**
+ * vmw_kms_srf_ok - check if a surface can be created
+ *
+ * @width: requested width
+ * @height: requested height
+ *
+ * Surfaces need to be less than texture size
+ */
+static bool
+vmw_kms_srf_ok(struct vmw_private *dev_priv, uint32_t width, uint32_t height)
+{
+	if (width  > dev_priv->texture_max_width ||
+	    height > dev_priv->texture_max_height)
+		return false;
+
+	return true;
+}
+
+/**
  * vmw_kms_new_framebuffer - Create a new framebuffer.
  *
  * @dev_priv: Pointer to device private struct.
@@ -912,7 +930,8 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
 	 * therefore, wrap the DMA buf in a surface so we can use the
 	 * SurfaceCopy command.
 	 */
-	if (dmabuf && only_2d &&
+	if (vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)  &&
+	    dmabuf && only_2d &&
 	    dev_priv->active_display_unit == vmw_du_screen_target) {
 		ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd,
 					      dmabuf, &surface);
@@ -1005,6 +1024,15 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
 	if (ret)
 		goto err_out;
 
+
+	if (!bo && !vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
+		DRM_ERROR("Surface size cannot exceed %dx%d",
+			dev_priv->texture_max_width,
+			dev_priv->texture_max_height);
+		goto err_out;
+	}
+
+
 	vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface,
 				      !(dev_priv->capabilities & SVGA_CAP_3D),
 				      mode_cmd);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index b27cd18..15e98a5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -106,6 +106,10 @@ struct vmw_screen_target_display_unit {
 	enum stdu_content_type content_fb_type;
 
 	bool defined;
+
+	/* For CPU Blit */
+	struct ttm_bo_kmap_obj host_map, guest_map;
+	unsigned int cpp;
 };
 
 
@@ -483,9 +487,50 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
 
 		/* Transfer the reference */
 		stdu->display_srf = new_display_srf;
-		new_display_srf = NULL;
 	}
 
+	/*
+	 * This should only happen if the DMA buf is too large to create a
+	 * proxy surface for.
+	 * If we are a 2D VM with a DMA buffer then we have to use CPU blit
+	 * so cache these mappings
+	 */
+	if (new_content_type == SEPARATE_DMA &&
+	    !(dev_priv->capabilities & SVGA_CAP_3D)) {
+
+		struct vmw_framebuffer_dmabuf *new_vfbd;
+
+		new_vfbd = vmw_framebuffer_to_vfbd(new_fb);
+
+		ret = ttm_bo_reserve(&new_vfbd->buffer->base, false, false,
+				     NULL);
+		if (ret)
+			goto out_srf_unpin;
+
+		ret = ttm_bo_kmap(&new_vfbd->buffer->base, 0,
+				  new_vfbd->buffer->base.num_pages,
+				  &stdu->guest_map);
+
+		ttm_bo_unreserve(&new_vfbd->buffer->base);
+
+		if (ret) {
+			DRM_ERROR("Failed to map content buffer to CPU\n");
+			goto out_srf_unpin;
+		}
+
+		ret = ttm_bo_kmap(&new_display_srf->res.backup->base, 0,
+				  new_display_srf->res.backup->base.num_pages,
+				  &stdu->host_map);
+		if (ret) {
+			DRM_ERROR("Failed to map display buffer to CPU\n");
+			ttm_bo_kunmap(&stdu->guest_map);
+			goto out_srf_unpin;
+		}
+
+		stdu->cpp = new_fb->pitches[0] / new_fb->width;
+	}
+
+
 	crtc->primary->fb = new_fb;
 	stdu->content_fb_type = new_content_type;
 	return 0;
@@ -572,6 +617,12 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
 		if (ret)
 			return ret;
 
+		if (stdu->guest_map.virtual)
+			ttm_bo_kunmap(&stdu->guest_map);
+
+		if (stdu->host_map.virtual)
+			ttm_bo_kunmap(&stdu->host_map);
+
 		vmw_stdu_unpin_display(stdu);
 		(void) vmw_stdu_update_st(dev_priv, stdu);
 		vmw_kms_del_active(dev_priv, &stdu->base);
@@ -791,6 +842,130 @@ static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty)
 	ddirty->right = ddirty->bottom = S32_MIN;
 }
 
+
+/**
+ * vmw_stdu_dmabuf_cpu_clip - Callback to encode a CPU blit
+ *
+ * @dirty: The closure structure.
+ *
+ * This function calculates the bounding box for all the incoming clips
+ */
+static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty)
+{
+	struct vmw_stdu_dirty *ddirty =
+		container_of(dirty, struct vmw_stdu_dirty, base);
+
+	dirty->num_hits = 1;
+
+	/* Calculate 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_dmabuf_cpu_commit - Callback to do a CPU blit from DMAbuf
+ *
+ * @dirty: The closure structure.
+ *
+ * For the special case when we cannot create a proxy surface in a
+ * 2D VM, we have to do a CPU blit ourselves.
+ */
+static void vmw_stdu_dmabuf_cpu_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);
+	s32 width, height;
+	s32 src_pitch, dst_pitch;
+	u8 *src, *dst;
+	bool not_used;
+
+
+	if (!dirty->num_hits)
+		return;
+
+	width = ddirty->right - ddirty->left;
+	height = ddirty->bottom - ddirty->top;
+
+	if (width == 0 || height == 0)
+		return;
+
+
+	/* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */
+	src_pitch = stdu->display_srf->base_size.width * stdu->cpp;
+	src = ttm_kmap_obj_virtual(&stdu->host_map, &not_used);
+	src += dirty->unit_y1 * src_pitch + dirty->unit_x1 * stdu->cpp;
+
+	dst_pitch = ddirty->pitch;
+	dst = ttm_kmap_obj_virtual(&stdu->guest_map, &not_used);
+	dst += dirty->fb_y * dst_pitch + dirty->fb_x * stdu->cpp;
+
+
+	/* Figure out the real direction */
+	if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
+		u8 *tmp;
+		s32 tmp_pitch;
+
+		tmp = src;
+		tmp_pitch = src_pitch;
+
+		src = dst;
+		src_pitch = dst_pitch;
+
+		dst = tmp;
+		dst_pitch = tmp_pitch;
+	}
+
+	/* CPU Blit */
+	while (height-- > 0) {
+		memcpy(dst, src, width * stdu->cpp);
+		dst += dst_pitch;
+		src += src_pitch;
+	}
+
+	if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
+		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 = ddirty->left;
+		region.x2 = ddirty->right;
+		region.y1 = ddirty->top;
+		region.y2 = ddirty->bottom;
+		ret = vmw_kms_update_proxy(
+			(struct vmw_resource *) &stdu->display_srf->res,
+			(const struct drm_clip_rect *) &region, 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,
+					 ddirty->left, ddirty->right,
+					 ddirty->top, ddirty->bottom);
+
+		vmw_fifo_commit(dev_priv, sizeof(*cmd));
+	}
+
+out_cleanup:
+	ddirty->left = ddirty->top = S32_MAX;
+	ddirty->right = ddirty->bottom = S32_MIN;
+}
+
+
 /**
  * vmw_kms_stdu_dma - Perform a DMA transfer between a dma-buffer backed
  * framebuffer and the screen target system.
@@ -849,6 +1024,13 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
 	if (to_surface)
 		ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update);
 
+	/* 2D VMs cannot use SVGA_3D_CMD_SURFACE_DMA so do CPU blit instead */
+	if (!(dev_priv->capabilities & SVGA_CAP_3D)) {
+		ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit;
+		ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip;
+		ddirty.base.fifo_reserve_size = 0;
+	}
+
 	ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips,
 				   0, 0, num_clips, increment, &ddirty.base);
 	vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
@@ -1201,6 +1383,31 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
 
 	dev_priv->active_display_unit = vmw_du_screen_target;
 
+	if (dev_priv->capabilities & SVGA_CAP_3D) {
+		/*
+		 * For 3D VMs, display (scanout) buffer size is the smaller of
+		 * max texture and max STDU
+		 */
+		uint32_t max_width, max_height;
+
+		max_width = min(dev_priv->texture_max_width,
+				dev_priv->stdu_max_width);
+		max_height = min(dev_priv->texture_max_height,
+				 dev_priv->stdu_max_height);
+
+		dev->mode_config.max_width = max_width;
+		dev->mode_config.max_height = max_height;
+	} else {
+		/*
+		 * Given various display aspect ratios, there's no way to
+		 * estimate these using prim_bb_mem.  So just set these to
+		 * something arbitrarily large and we will reject any layout
+		 * that doesn't fit prim_bb_mem later
+		 */
+		dev->mode_config.max_width = 16384;
+		dev->mode_config.max_height = 16384;
+	}
+
 	vmw_kms_create_implicit_placement_property(dev_priv, false);
 
 	for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] drm/vmwgfx: Fix large topology crash
  2017-08-21 20:10 [PATCH 0/3]: Large topology fix Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 1/3] drm/vmwgfx: Support topology greater than texture size Sinclair Yeh
@ 2017-08-21 20:10 ` Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 3/3] drm/vmwgfx: Limit max desktop dimensions to 8Kx8K Sinclair Yeh
  2 siblings, 0 replies; 4+ messages in thread
From: Sinclair Yeh @ 2017-08-21 20:10 UTC (permalink / raw)
  To: stable; +Cc: Sinclair Yeh

The previous attempt at this had an issue with with num_clips > 1
because it would always end up using the coordinates of the last
clip while using width and height calculated from the bounding
box of all the clips.

So if the last clip happens to be not at the top-left corner of
the bounding box, the CPU blit operation would go out of bounds.

The original intent was to coalesce all the clips into one blit,
and to do that we need to also track the starting point of the
content buffer.

Commit a1ac63391230 upstream.
Cc: <stable@vger.kernel.org> # 4.11.x

Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 15e98a5..55716d0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -53,6 +53,8 @@ enum stdu_content_type {
  * @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
  * @buf: DMA buffer when DMA-ing between buffer and screen targets.
  * @sid: Surface ID when copying between surface and screen targets.
  */
@@ -60,6 +62,7 @@ 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_dma_buffer *buf;
@@ -848,7 +851,7 @@ static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty)
  *
  * @dirty: The closure structure.
  *
- * This function calculates the bounding box for all the incoming clips
+ * This function calculates the bounding box for all the incoming clips.
  */
 static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty)
 {
@@ -857,11 +860,19 @@ static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty)
 
 	dirty->num_hits = 1;
 
-	/* Calculate bounding box */
+	/* Calculate 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);
+
+	/*
+	 * Calculate content bounding box.  We only need the top-left
+	 * coordinate because width and height will be the same as the
+	 * destination bounding box above
+	 */
+	ddirty->fb_left = min_t(s32, ddirty->fb_left, dirty->fb_x);
+	ddirty->fb_top  = min_t(s32, ddirty->fb_top, dirty->fb_y);
 }
 
 
@@ -898,11 +909,11 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
 	/* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */
 	src_pitch = stdu->display_srf->base_size.width * stdu->cpp;
 	src = ttm_kmap_obj_virtual(&stdu->host_map, &not_used);
-	src += dirty->unit_y1 * src_pitch + dirty->unit_x1 * stdu->cpp;
+	src += ddirty->top * src_pitch + ddirty->left * stdu->cpp;
 
 	dst_pitch = ddirty->pitch;
 	dst = ttm_kmap_obj_virtual(&stdu->guest_map, &not_used);
-	dst += dirty->fb_y * dst_pitch + dirty->fb_x * stdu->cpp;
+	dst += ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp;
 
 
 	/* Figure out the real direction */
@@ -961,7 +972,7 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
 	}
 
 out_cleanup:
-	ddirty->left = ddirty->top = S32_MAX;
+	ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX;
 	ddirty->right = ddirty->bottom = S32_MIN;
 }
 
@@ -1014,6 +1025,7 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
 		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_dmabuf_fifo_commit;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] drm/vmwgfx: Limit max desktop dimensions to 8Kx8K
  2017-08-21 20:10 [PATCH 0/3]: Large topology fix Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 1/3] drm/vmwgfx: Support topology greater than texture size Sinclair Yeh
  2017-08-21 20:10 ` [PATCH 2/3] drm/vmwgfx: Fix large topology crash Sinclair Yeh
@ 2017-08-21 20:10 ` Sinclair Yeh
  2 siblings, 0 replies; 4+ messages in thread
From: Sinclair Yeh @ 2017-08-21 20:10 UTC (permalink / raw)
  To: stable; +Cc: Sinclair Yeh

This was originally chosen to be an arbitrarily large number.  However,
some user mode may actually try to set a 16Kx16K mode and run into other
issues.

Since 8Kx8K is the current texture limit for Mesa LLVM driver, we will
just use this limit for now.

Commit 7b009e76797c upstream.
Cc: <stable@vger.kernel.org> # 4.11.x

Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 55716d0..b150e3d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1416,8 +1416,8 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
 		 * something arbitrarily large and we will reject any layout
 		 * that doesn't fit prim_bb_mem later
 		 */
-		dev->mode_config.max_width = 16384;
-		dev->mode_config.max_height = 16384;
+		dev->mode_config.max_width = 8192;
+		dev->mode_config.max_height = 8192;
 	}
 
 	vmw_kms_create_implicit_placement_property(dev_priv, false);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-08-21 20:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-21 20:10 [PATCH 0/3]: Large topology fix Sinclair Yeh
2017-08-21 20:10 ` [PATCH 1/3] drm/vmwgfx: Support topology greater than texture size Sinclair Yeh
2017-08-21 20:10 ` [PATCH 2/3] drm/vmwgfx: Fix large topology crash Sinclair Yeh
2017-08-21 20:10 ` [PATCH 3/3] drm/vmwgfx: Limit max desktop dimensions to 8Kx8K Sinclair Yeh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.