It looks like Hyper-V supports a hardware cursor feature. It is not used by Linux VM, but the Hyper-V host still draws a point as an extra mouse pointer, which is unwanted, especially when Xorg is running.
The hyperv_fb driver uses synthvid_send_ptr() to hide the unwanted pointer. When the hyperv_drm driver was developed, the function synthvid_send_ptr() was not copied from the hyperv_fb driver. Fix the issue by adding the function into hyperv_drm.
Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device") Signed-off-by: Dexuan Cui decui@microsoft.com Cc: Deepak Rawat drawat.floss@gmail.com Cc: Haiyang Zhang haiyangz@microsoft.com --- drivers/gpu/drm/hyperv/hyperv_drm.h | 1 + drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 1 + drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 39 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm.h b/drivers/gpu/drm/hyperv/hyperv_drm.h index 886add4f9cd0..27bfd27c05be 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm.h +++ b/drivers/gpu/drm/hyperv/hyperv_drm.h @@ -46,6 +46,7 @@ int hyperv_mode_config_init(struct hyperv_drm_device *hv); int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t vram_pp); int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp, u32 w, u32 h, u32 pitch); +int hyperv_send_ptr(struct hv_device *hdev); int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect); int hyperv_connect_vsp(struct hv_device *hdev);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 3aaee4730ec6..e21c82cf3326 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -101,6 +101,7 @@ static void hyperv_pipe_enable(struct drm_simple_display_pipe *pipe, struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ hyperv_send_ptr(hv->hdev); hyperv_update_situation(hv->hdev, 1, hv->screen_depth, crtc_state->mode.hdisplay, crtc_state->mode.vdisplay, diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 6d4bdccfbd1a..1ea7a0432320 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -299,6 +299,40 @@ int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp, return 0; }
+/* Send mouse pointer info to host */ +int hyperv_send_ptr(struct hv_device *hdev) +{ + struct synthvid_msg msg; + + memset(&msg, 0, sizeof(struct synthvid_msg)); + msg.vid_hdr.type = SYNTHVID_POINTER_POSITION; + msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + + sizeof(struct synthvid_pointer_position); + msg.ptr_pos.is_visible = 1; + msg.ptr_pos.video_output = 0; + msg.ptr_pos.image_x = 0; + msg.ptr_pos.image_y = 0; + hyperv_sendpacket(hdev, &msg); + + memset(&msg, 0, sizeof(struct synthvid_msg)); + msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE; + msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + + sizeof(struct synthvid_pointer_shape); + msg.ptr_shape.part_idx = SYNTHVID_CURSOR_COMPLETE; + msg.ptr_shape.is_argb = 1; + msg.ptr_shape.width = 1; + msg.ptr_shape.height = 1; + msg.ptr_shape.hot_x = 0; + msg.ptr_shape.hot_y = 0; + msg.ptr_shape.data[0] = 0; + msg.ptr_shape.data[1] = 1; + msg.ptr_shape.data[2] = 1; + msg.ptr_shape.data[3] = 1; + hyperv_sendpacket(hdev, &msg); + + return 0; +} + int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect) { struct hyperv_drm_device *hv = hv_get_drvdata(hdev); @@ -392,8 +426,11 @@ static void hyperv_receive_sub(struct hv_device *hdev) return; }
- if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) + if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) { hv->dirt_needed = msg->feature_chg.is_dirt_needed; + if (hv->dirt_needed) + hyperv_send_ptr(hv->hdev); + } }
static void hyperv_receive(void *ctx)
-----Original Message----- From: Dexuan Cui decui@microsoft.com Sent: Monday, September 13, 2021 2:27 PM To: drawat.floss@gmail.com; Haiyang Zhang haiyangz@microsoft.com; airlied@linux.ie; daniel@ffwll.ch; tzimmermann@suse.de; dri- devel@lists.freedesktop.org Cc: linux-hyperv@vger.kernel.org; linux-kernel@vger.kernel.org; Dexuan Cui decui@microsoft.com Subject: [PATCH] drm/hyperv: Fix double mouse pointers
It looks like Hyper-V supports a hardware cursor feature. It is not used by Linux VM, but the Hyper-V host still draws a point as an extra mouse pointer, which is unwanted, especially when Xorg is running.
The hyperv_fb driver uses synthvid_send_ptr() to hide the unwanted pointer. When the hyperv_drm driver was developed, the function synthvid_send_ptr() was not copied from the hyperv_fb driver. Fix the issue by adding the function into hyperv_drm.
Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device") Signed-off-by: Dexuan Cui decui@microsoft.com Cc: Deepak Rawat drawat.floss@gmail.com Cc: Haiyang Zhang haiyangz@microsoft.com
drivers/gpu/drm/hyperv/hyperv_drm.h | 1 + drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 1 + drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 39 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-)
Thank you! Reviewed-by: Haiyang Zhang haiyangz@microsoft.com
Thanks Dexuan, for the patch. A minor comment below.
On Mon, Sep 13, 2021 at 11:27 AM Dexuan Cui decui@microsoft.com wrote:
It looks like Hyper-V supports a hardware cursor feature. It is not used by Linux VM, but the Hyper-V host still draws a point as an extra mouse pointer, which is unwanted, especially when Xorg is running.
The hyperv_fb driver uses synthvid_send_ptr() to hide the unwanted pointer. When the hyperv_drm driver was developed, the function synthvid_send_ptr() was not copied from the hyperv_fb driver. Fix the issue by adding the function into hyperv_drm.
Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device") Signed-off-by: Dexuan Cui decui@microsoft.com Cc: Deepak Rawat drawat.floss@gmail.com Cc: Haiyang Zhang haiyangz@microsoft.com
drivers/gpu/drm/hyperv/hyperv_drm.h | 1 + drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 1 + drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 39 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm.h b/drivers/gpu/drm/hyperv/hyperv_drm.h index 886add4f9cd0..27bfd27c05be 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm.h +++ b/drivers/gpu/drm/hyperv/hyperv_drm.h @@ -46,6 +46,7 @@ int hyperv_mode_config_init(struct hyperv_drm_device *hv); int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t vram_pp); int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp, u32 w, u32 h, u32 pitch); +int hyperv_send_ptr(struct hv_device *hdev); int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect); int hyperv_connect_vsp(struct hv_device *hdev);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 3aaee4730ec6..e21c82cf3326 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -101,6 +101,7 @@ static void hyperv_pipe_enable(struct drm_simple_display_pipe *pipe, struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
hyperv_send_ptr(hv->hdev); hyperv_update_situation(hv->hdev, 1, hv->screen_depth, crtc_state->mode.hdisplay, crtc_state->mode.vdisplay,
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 6d4bdccfbd1a..1ea7a0432320 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -299,6 +299,40 @@ int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp, return 0; }
+/* Send mouse pointer info to host */ +int hyperv_send_ptr(struct hv_device *hdev) +{
struct synthvid_msg msg;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_position);
msg.ptr_pos.is_visible = 1;
"is_visible" should be 0 since you want to hide the pointer. Maybe better, accept these from the caller.
msg.ptr_pos.video_output = 0;
msg.ptr_pos.image_x = 0;
msg.ptr_pos.image_y = 0;
hyperv_sendpacket(hdev, &msg);
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_shape);
msg.ptr_shape.part_idx = SYNTHVID_CURSOR_COMPLETE;
msg.ptr_shape.is_argb = 1;
msg.ptr_shape.width = 1;
msg.ptr_shape.height = 1;
msg.ptr_shape.hot_x = 0;
msg.ptr_shape.hot_y = 0;
msg.ptr_shape.data[0] = 0;
msg.ptr_shape.data[1] = 1;
msg.ptr_shape.data[2] = 1;
msg.ptr_shape.data[3] = 1;
hyperv_sendpacket(hdev, &msg);
Is it necessary to send SYNTHVID_POINTER_SHAPE here? Perhaps we should separate SYNTHVID_POINTER_POSITION and SYNTHVID_POINTER_SHAPE into different functions.
return 0;
+}
int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect) { struct hyperv_drm_device *hv = hv_get_drvdata(hdev); @@ -392,8 +426,11 @@ static void hyperv_receive_sub(struct hv_device *hdev) return; }
if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE)
if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) { hv->dirt_needed = msg->feature_chg.is_dirt_needed;
if (hv->dirt_needed)
hyperv_send_ptr(hv->hdev);
}
}
static void hyperv_receive(void *ctx)
2.25.1
-----Original Message----- From: Deepak Rawat drawat.floss@gmail.com Sent: Tuesday, September 14, 2021 11:59 AM To: Dexuan Cui decui@microsoft.com Cc: Haiyang Zhang haiyangz@microsoft.com; David Airlie airlied@linux.ie; Daniel Vetter daniel@ffwll.ch; Thomas Zimmermann tzimmermann@suse.de; dri-devel@lists.freedesktop.org; linux- hyperv@vger.kernel.org; linux-kernel@vger.kernel.org Subject: Re: [PATCH] drm/hyperv: Fix double mouse pointers
Thanks Dexuan, for the patch. A minor comment below.
On Mon, Sep 13, 2021 at 11:27 AM Dexuan Cui decui@microsoft.com wrote:
It looks like Hyper-V supports a hardware cursor feature. It is not
used
by Linux VM, but the Hyper-V host still draws a point as an extra
mouse
pointer, which is unwanted, especially when Xorg is running.
The hyperv_fb driver uses synthvid_send_ptr() to hide the unwanted
pointer.
When the hyperv_drm driver was developed, the function
synthvid_send_ptr()
was not copied from the hyperv_fb driver. Fix the issue by adding the function into hyperv_drm.
Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic
video device")
Signed-off-by: Dexuan Cui decui@microsoft.com Cc: Deepak Rawat drawat.floss@gmail.com Cc: Haiyang Zhang haiyangz@microsoft.com
drivers/gpu/drm/hyperv/hyperv_drm.h | 1 + drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 1 + drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 39
++++++++++++++++++++-
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm.h
b/drivers/gpu/drm/hyperv/hyperv_drm.h
index 886add4f9cd0..27bfd27c05be 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm.h +++ b/drivers/gpu/drm/hyperv/hyperv_drm.h @@ -46,6 +46,7 @@ int hyperv_mode_config_init(struct hyperv_drm_device
*hv);
int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t
vram_pp);
int hyperv_update_situation(struct hv_device *hdev, u8 active, u32
bpp,
u32 w, u32 h, u32 pitch);
+int hyperv_send_ptr(struct hv_device *hdev); int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect); int hyperv_connect_vsp(struct hv_device *hdev);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 3aaee4730ec6..e21c82cf3326 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -101,6 +101,7 @@ static void hyperv_pipe_enable(struct
drm_simple_display_pipe *pipe,
struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev); struct drm_shadow_plane_state *shadow_plane_state =
to_drm_shadow_plane_state(plane_state);
hyperv_send_ptr(hv->hdev); hyperv_update_situation(hv->hdev, 1, hv->screen_depth, crtc_state->mode.hdisplay, crtc_state->mode.vdisplay,
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
index 6d4bdccfbd1a..1ea7a0432320 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -299,6 +299,40 @@ int hyperv_update_situation(struct hv_device
*hdev, u8 active, u32 bpp,
return 0;
}
+/* Send mouse pointer info to host */ +int hyperv_send_ptr(struct hv_device *hdev) +{
struct synthvid_msg msg;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_position);
msg.ptr_pos.is_visible = 1;
"is_visible" should be 0 since you want to hide the pointer. Maybe better, accept these from the caller.
I believe I tried is_visible = 0 during my implementation of the hyperv_fb. It still have the host cursor visible... So I had to set the cursor color's alpha value = 0 to make it transparent. But you may try is_visible = 0 again.
Thanks, - Haiyang
From: Deepak Rawat drawat.floss@gmail.com Sent: Tuesday, September 14, 2021 8:59 AM ...
+/* Send mouse pointer info to host */ +int hyperv_send_ptr(struct hv_device *hdev) +{
struct synthvid_msg msg;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_position);
msg.ptr_pos.is_visible = 1;
"is_visible" should be 0 since you want to hide the pointer. Maybe better, accept these from the caller.
According to my test, "is_visible = 0" doesn't work, i.e. can't hide the unwanted HW mouse poiner. It looks like the field is for some very old legacy Windows VMs like Windows Vista.
Haiyang also replied in another email, saying "is_visible = 0" doesn't work.
msg.ptr_pos.video_output = 0;
msg.ptr_pos.image_x = 0;
msg.ptr_pos.image_y = 0;
hyperv_sendpacket(hdev, &msg);
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_shape);
msg.ptr_shape.part_idx = SYNTHVID_CURSOR_COMPLETE;
msg.ptr_shape.is_argb = 1;
msg.ptr_shape.width = 1;
msg.ptr_shape.height = 1;
msg.ptr_shape.hot_x = 0;
msg.ptr_shape.hot_y = 0;
msg.ptr_shape.data[0] = 0;
msg.ptr_shape.data[1] = 1;
msg.ptr_shape.data[2] = 1;
msg.ptr_shape.data[3] = 1;
hyperv_sendpacket(hdev, &msg);
Is it necessary to send SYNTHVID_POINTER_SHAPE here? Perhaps we should
According to my test, yes. If I don't send a SYNTHVID_POINTER_SHAPE message, the unwanted mouse pointer can't be hidden. As we know, the protocol between the VSC and the VSP is not well documented to us. I can ask Hyper-V team for some clarification on this, but it's probably we can just use the current version of hiding the mouse pointer as-is -- this has been used for 10+ years in the hyperv_fb driver without any issue. :-)
separate SYNTHVID_POINTER_POSITION and SYNTHVID_POINTER_SHAPE into different functions.
Since the 2 messages are only used here, I suggest we keep it as-is.
Thanks, -- Dexuan
HI Dexuan, thanks for confirming. Could you please add this as a comment to the function.
Reviewed-by: Deepak Rawat drawat.floss@gmail.com
On Tue, Sep 14, 2021 at 11:59 PM Dexuan Cui decui@microsoft.com wrote:
From: Deepak Rawat drawat.floss@gmail.com Sent: Tuesday, September 14, 2021 8:59 AM ...
+/* Send mouse pointer info to host */ +int hyperv_send_ptr(struct hv_device *hdev) +{
struct synthvid_msg msg;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_position);
msg.ptr_pos.is_visible = 1;
"is_visible" should be 0 since you want to hide the pointer. Maybe better, accept these from the caller.
According to my test, "is_visible = 0" doesn't work, i.e. can't hide the unwanted HW mouse poiner. It looks like the field is for some very old legacy Windows VMs like Windows Vista.
Haiyang also replied in another email, saying "is_visible = 0" doesn't work.
msg.ptr_pos.video_output = 0;
msg.ptr_pos.image_x = 0;
msg.ptr_pos.image_y = 0;
hyperv_sendpacket(hdev, &msg);
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_pointer_shape);
msg.ptr_shape.part_idx = SYNTHVID_CURSOR_COMPLETE;
msg.ptr_shape.is_argb = 1;
msg.ptr_shape.width = 1;
msg.ptr_shape.height = 1;
msg.ptr_shape.hot_x = 0;
msg.ptr_shape.hot_y = 0;
msg.ptr_shape.data[0] = 0;
msg.ptr_shape.data[1] = 1;
msg.ptr_shape.data[2] = 1;
msg.ptr_shape.data[3] = 1;
hyperv_sendpacket(hdev, &msg);
Is it necessary to send SYNTHVID_POINTER_SHAPE here? Perhaps we should
According to my test, yes. If I don't send a SYNTHVID_POINTER_SHAPE message, the unwanted mouse pointer can't be hidden. As we know, the protocol between the VSC and the VSP is not well documented to us. I can ask Hyper-V team for some clarification on this, but it's probably we can just use the current version of hiding the mouse pointer as-is -- this has been used for 10+ years in the hyperv_fb driver without any issue. :-)
separate SYNTHVID_POINTER_POSITION and SYNTHVID_POINTER_SHAPE into different functions.
Since the 2 messages are only used here, I suggest we keep it as-is.
Thanks, -- Dexuan
From: Deepak Rawat drawat.floss@gmail.com Sent: Thursday, September 16, 2021 9:17 AM To: Dexuan Cui decui@microsoft.com Cc: Haiyang Zhang haiyangz@microsoft.com; David Airlie airlied@linux.ie; Daniel Vetter daniel@ffwll.ch; Thomas Zimmermann tzimmermann@suse.de; dri-devel@lists.freedesktop.org; linux-hyperv@vger.kernel.org; linux-kernel@vger.kernel.org Subject: Re: [PATCH] drm/hyperv: Fix double mouse pointers
HI Dexuan, thanks for confirming. Could you please add this as a comment to the function.
Reviewed-by: Deepak Rawat drawat.floss@gmail.com
Thanks, Deepak! Will do, and I'll rename the function to hyperv_hide_hw_ptr() to better express the intent of the function.
dri-devel@lists.freedesktop.org