All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host
@ 2019-08-21 11:10 Wei Hu
  2019-08-21 23:48 ` Michael Kelley
  0 siblings, 1 reply; 3+ messages in thread
From: Wei Hu @ 2019-08-21 11:10 UTC (permalink / raw)
  To: b.zolnierkie, linux-hyperv, dri-devel, linux-fbdev, linux-kernel,
	sashal, Stephen Hemminger, Haiyang Zhang, KY Srinivasan,
	Dexuan Cui, Michael Kelley
  Cc: Wei Hu, Iouri Tarassov

Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
The "video=hyperv_fb" boot time option is not needed, but still can be
used to overwrite what the host specifies. The VM resolution on the host
could be set by executing the powershell "set-vmvideo" command.

v2:
- Implemented fallback when version negotiation failed.
- Defined full size for supported_resolution array.

Signed-off-by: Iouri Tarassov <iourit@microsoft.com>
Signed-off-by: Wei Hu <weh@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
---
 drivers/video/fbdev/hyperv_fb.c | 145 +++++++++++++++++++++++++++++---
 1 file changed, 133 insertions(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..2ca400c0d621 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -23,6 +23,14 @@
  *
  * Portrait orientation is also supported:
  *     For example: video=hyperv_fb:864x1152
+ *
+ * When a Windows 10 RS5+ host is used, the virtual machine screen
+ * resolution is obtained from the host. The "video=hyperv_fb" option is
+ * not needed, but still can be used to overwrite what the host specifies.
+ * The VM resolution on the host could be set by executing the powershell
+ * "set-vmvideo" command. For example
+ *     set-vmvideo -vmname name -horizontalresolution:1920 \
+ * -verticalresolution:1200 -resolutiontype single
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -44,6 +52,7 @@
 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
 
 #define SYNTHVID_DEPTH_WIN7 16
 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +91,25 @@ enum synthvid_msg_type {
 	SYNTHVID_POINTER_SHAPE		= 8,
 	SYNTHVID_FEATURE_CHANGE		= 9,
 	SYNTHVID_DIRT			= 10,
+	SYNTHVID_RESOLUTION_REQUEST	= 13,
+	SYNTHVID_RESOLUTION_RESPONSE	= 14,
 
-	SYNTHVID_MAX			= 11
+	SYNTHVID_MAX			= 15
 };
 
+#define		SYNTHVID_EDID_BLOCK_SIZE	128
+#define		SYNTHVID_MAX_RESOLUTION_COUNT	64
+
+struct hvd_screen_info {
+	u16 width;
+	u16 height;
+} __packed;
+
 struct synthvid_msg_hdr {
 	u32 type;
 	u32 size;  /* size of this header + payload after this field*/
 } __packed;
 
-
 struct synthvid_version_req {
 	u32 version;
 } __packed;
@@ -102,6 +120,19 @@ struct synthvid_version_resp {
 	u8 max_video_outputs;
 } __packed;
 
+struct synthvid_supported_resolution_req {
+	u8 maximum_resolution_count;
+} __packed;
+
+struct synthvid_supported_resolution_resp {
+	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
+	u8 resolution_count;
+	u8 default_resolution_index;
+	u8 is_standard;
+	struct hvd_screen_info
+		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
+} __packed;
+
 struct synthvid_vram_location {
 	u64 user_ctx;
 	u8 is_vram_gpa_specified;
@@ -187,6 +218,8 @@ struct synthvid_msg {
 		struct synthvid_pointer_shape ptr_shape;
 		struct synthvid_feature_change feature_chg;
 		struct synthvid_dirt dirt;
+		struct synthvid_supported_resolution_req resolution_req;
+		struct synthvid_supported_resolution_resp resolution_resp;
 	};
 } __packed;
 
@@ -224,6 +257,8 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
+static uint screen_width_max = HVFB_WIDTH;
+static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 
@@ -354,6 +389,7 @@ static void synthvid_recv_sub(struct hv_device *hdev)
 
 	/* Complete the wait event */
 	if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+	    msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
 	    msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
 		memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
 		complete(&par->wait);
@@ -428,6 +464,64 @@ static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
 	}
 
 	par->synthvid_version = ver;
+	pr_info("Synthvid Version major %d, minor %d\n",
+		ver & 0x0000ffff, (ver & 0xffff0000) >> 16);
+
+out:
+	return ret;
+}
+
+/* Get current resolution from the host */
+static int synthvid_get_supported_resolution(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par = info->par;
+	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+	int ret = 0;
+	unsigned long t;
+	u8 index;
+	int i;
+
+	memset(msg, 0, sizeof(struct synthvid_msg));
+	msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
+	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_supported_resolution_req);
+
+	msg->resolution_req.maximum_resolution_count =
+		SYNTHVID_MAX_RESOLUTION_COUNT;
+	synthvid_send(hdev, msg);
+
+	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+	if (!t) {
+		pr_err("Time out on waiting resolution response\n");
+			ret = -ETIMEDOUT;
+			goto out;
+	}
+
+	if (msg->resolution_resp.resolution_count == 0) {
+		pr_err("No supported resolutions\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	index = msg->resolution_resp.default_resolution_index;
+	if (index >= msg->resolution_resp.resolution_count) {
+		pr_err("Invalid resolution index: %d\n", index);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	for (i = 0; i < msg->resolution_resp.resolution_count; i++) {
+		screen_width_max = max_t(unsigned int, screen_width_max,
+		    msg->resolution_resp.supported_resolution[i].width);
+		screen_height_max = max_t(unsigned int, screen_height_max,
+		    msg->resolution_resp.supported_resolution[i].height);
+	}
+
+	screen_width =
+		msg->resolution_resp.supported_resolution[index].width;
+	screen_height =
+		msg->resolution_resp.supported_resolution[index].height;
 
 out:
 	return ret;
@@ -448,11 +542,27 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
 	}
 
 	/* Negotiate the protocol version with host */
-	if (vmbus_proto_version == VERSION_WS2008 ||
-	    vmbus_proto_version == VERSION_WIN7)
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
-	else
+	switch (vmbus_proto_version) {
+	case VERSION_WIN10:
+	case VERSION_WIN10_V5:
+		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
+		if (!ret)
+			break;
+		/* Fallthrough */
+	case VERSION_WIN8:
+	case VERSION_WIN8_1:
 		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
+		if (!ret)
+			break;
+		/* Fallthrough */
+	case VERSION_WS2008:
+	case VERSION_WIN7:
+		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
+		break;
+	default:
+		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
+		break;
+	}
 
 	if (ret) {
 		pr_err("Synthetic video device version not accepted\n");
@@ -464,6 +574,12 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
 	else
 		screen_depth = SYNTHVID_DEPTH_WIN8;
 
+	if (par->synthvid_version >= SYNTHVID_VERSION_WIN10) {
+		ret = synthvid_get_supported_resolution(hdev);
+		if (ret)
+			pr_info("Failed to get supported resolution from host, use default\n");
+	}
+
 	screen_fb_size = hdev->channel->offermsg.offer.
 				mmio_megabytes * 1024 * 1024;
 
@@ -653,6 +769,8 @@ static void hvfb_get_option(struct fb_info *info)
 	}
 
 	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
+	    (par->synthvid_version >= SYNTHVID_VERSION_WIN10 &&
+	    (x > screen_width_max || y > screen_height_max)) ||
 	    (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
 	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
 	    (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
@@ -689,8 +807,12 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
 		}
 
 		if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
-		    pci_resource_len(pdev, 0) < screen_fb_size)
+		    pci_resource_len(pdev, 0) < screen_fb_size) {
+			pr_err("Resource not available or (0x%lx < 0x%lx)\n",
+			       (unsigned long) pci_resource_len(pdev, 0),
+			       (unsigned long) screen_fb_size);
 			goto err1;
+		}
 
 		pot_end = pci_resource_end(pdev, 0);
 		pot_start = pot_end - screen_fb_size + 1;
@@ -781,17 +903,16 @@ static int hvfb_probe(struct hv_device *hdev,
 		goto error1;
 	}
 
+	hvfb_get_option(info);
+	pr_info("Screen resolution: %dx%d, Color depth: %d\n",
+		screen_width, screen_height, screen_depth);
+
 	ret = hvfb_getmem(hdev, info);
 	if (ret) {
 		pr_err("No memory for framebuffer\n");
 		goto error2;
 	}
 
-	hvfb_get_option(info);
-	pr_info("Screen resolution: %dx%d, Color depth: %d\n",
-		screen_width, screen_height, screen_depth);
-
-
 	/* Set up fb_info */
 	info->flags = FBINFO_DEFAULT;
 
-- 
2.20.1


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

* RE: [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host
  2019-08-21 11:10 [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host Wei Hu
@ 2019-08-21 23:48 ` Michael Kelley
  2019-08-27  8:02   ` Wei Hu
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Kelley @ 2019-08-21 23:48 UTC (permalink / raw)
  To: Wei Hu, b.zolnierkie, linux-hyperv, dri-devel, linux-fbdev,
	linux-kernel, sashal, Stephen Hemminger, Haiyang Zhang,
	KY Srinivasan, Dexuan Cui
  Cc: Iouri Tarassov

From: Wei Hu <weh@microsoft.com> Sent: Wednesday, August 21, 2019 4:11 AM
> 
> Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
> The "video=hyperv_fb" boot time option is not needed, but still can be
> used to overwrite what the host specifies. The VM resolution on the host
> could be set by executing the powershell "set-vmvideo" command.
> 
> v2:
> - Implemented fallback when version negotiation failed.
> - Defined full size for supported_resolution array.
> 
> Signed-off-by: Iouri Tarassov <iourit@microsoft.com>
> Signed-off-by: Wei Hu <weh@microsoft.com>
> Reviewed-by: Michael Kelley <mikelley@microsoft.com>

Reviewed-by: lines should not be added to patches until the reviewer
has actually given a "Reviewed-by:" statement, and I haven't done that
yet. :-)  Such statements are typically not given until review
comments have been addressed and re-reviewed as necessary.

> ---
>  drivers/video/fbdev/hyperv_fb.c | 145 +++++++++++++++++++++++++++++---
>  1 file changed, 133 insertions(+), 12 deletions(-)
> 
> +
> +struct synthvid_supported_resolution_resp {
> +	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
> +	u8 resolution_count;
> +	u8 default_resolution_index;
> +	u8 is_standard;
> +	struct hvd_screen_info
> +		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];

Is there extra whitespace on this line?  Just wondering why it doesn't
line up.

> +} __packed;
> +
> @@ -448,11 +542,27 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
>  	}
> 
>  	/* Negotiate the protocol version with host */
> -	if (vmbus_proto_version == VERSION_WS2008 ||
> -	    vmbus_proto_version == VERSION_WIN7)
> -		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
> -	else
> +	switch (vmbus_proto_version) {
> +	case VERSION_WIN10:
> +	case VERSION_WIN10_V5:
> +		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
> +		if (!ret)
> +			break;
> +		/* Fallthrough */
> +	case VERSION_WIN8:
> +	case VERSION_WIN8_1:
>  		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
> +		if (!ret)
> +			break;
> +		/* Fallthrough */
> +	case VERSION_WS2008:
> +	case VERSION_WIN7:
> +		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
> +		break;
> +	default:
> +		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
> +		break;

I'm tempted to put "default:" up with VERSION_WIN10 and VERISON_WIN10_V5
so that it can also fallback to earlier versions.  You would have a couple of less
lines of code.  But arguably newer versions should always go with
SYNTHVID_VERSION_WIN10 and not fallback.  I don't have a strong opinion
either way.

> +	}
> 
>  	if (ret) {
>  		pr_err("Synthetic video device version not accepted\n");
> @@ -464,6 +574,12 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
>  	else
>  		screen_depth = SYNTHVID_DEPTH_WIN8;
> 
> +	if (par->synthvid_version >= SYNTHVID_VERSION_WIN10) {

Unfortunately, this "greater than" comparison won't work correctly because
the minor version is stored in the high order bits.  Version 4.0 would compare
as less than version 3.5 (which is what SYNTHVID_VERSION_WIN10 is).

> +		ret = synthvid_get_supported_resolution(hdev);
> +		if (ret)
> +			pr_info("Failed to get supported resolution from host, use
> default\n");
> +	}
> +
>  	screen_fb_size = hdev->channel->offermsg.offer.
>  				mmio_megabytes * 1024 * 1024;
> 
> @@ -653,6 +769,8 @@ static void hvfb_get_option(struct fb_info *info)
>  	}
> 
>  	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
> +	    (par->synthvid_version >= SYNTHVID_VERSION_WIN10 &&

Same comparison problem here.

> +	    (x > screen_width_max || y > screen_height_max)) ||
>  	    (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
>  	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
>  	    (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
> @@ -689,8 +807,12 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info
> *info)
>  		}
> 
>  		if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
> -		    pci_resource_len(pdev, 0) < screen_fb_size)
> +		    pci_resource_len(pdev, 0) < screen_fb_size) {
> +			pr_err("Resource not available or (0x%lx < 0x%lx)\n",
> +			       (unsigned long) pci_resource_len(pdev, 0),
> +			       (unsigned long) screen_fb_size);
>  			goto err1;
> +		}

Michael

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

* RE: [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host
  2019-08-21 23:48 ` Michael Kelley
@ 2019-08-27  8:02   ` Wei Hu
  0 siblings, 0 replies; 3+ messages in thread
From: Wei Hu @ 2019-08-27  8:02 UTC (permalink / raw)
  To: Michael Kelley, b.zolnierkie, linux-hyperv, dri-devel,
	linux-fbdev, linux-kernel, sashal, Stephen Hemminger,
	Haiyang Zhang, KY Srinivasan, Dexuan Cui
  Cc: Iouri Tarassov

> -----Original Message-----
> From: Michael Kelley <mikelley@microsoft.com>
> Sent: Thursday, August 22, 2019 7:49 AM
> To: Wei Hu <weh@microsoft.com>; b.zolnierkie@samsung.com; linux-
> hyperv@vger.kernel.org; dri-devel@lists.freedesktop.org; linux-
> fbdev@vger.kernel.org; linux-kernel@vger.kernel.org; sashal@kernel.org;
> Stephen Hemminger <sthemmin@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; KY Srinivasan <kys@microsoft.com>; Dexuan Cui
> <decui@microsoft.com>
> Cc: Iouri Tarassov <iourit@microsoft.com>
> > +
> > +struct synthvid_supported_resolution_resp {
> > +	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
> > +	u8 resolution_count;
> > +	u8 default_resolution_index;
> > +	u8 is_standard;
> > +	struct hvd_screen_info
> > +		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
> 
> Is there extra whitespace on this line?  Just wondering why it doesn't
> line up.
> 
[Wei Hu] 
No extra whitespace. It would be over 80 characters if I had put them in one line.

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

end of thread, other threads:[~2019-08-27  8:11 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-21 11:10 [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host Wei Hu
2019-08-21 23:48 ` Michael Kelley
2019-08-27  8:02   ` Wei Hu

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.