drm/vmwgfx: Fix 32-bit VMW_PORT_HB_[IN|OUT] macros
Subsystems (4)
PATCH 1/3 drm/vmwgfx: Fix 32-bit VMW_PORT_HB_[IN|OUT] macros
Depending on whether the kernel is compiled with frame-pointer or not, the temporary memory location used for the bp parameter in these macros is referenced relative to the stack pointer or the frame pointer. Hence we can never reference that parameter when we've modified either the stack pointer or the frame pointer, because then the compiler would generate an incorrect stack reference.
Fix this by pushing the temporary memory parameter on a known location on the stack before modifying the stack- and frame pointers.
--- drivers/gpu/drm/vmwgfx/vmwgfx_msg.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +17 -8
@@ -135,17 +135,24 @@#else -/* In the 32-bit version of this macro, we use "m" because there is no -* more register left for bp +/* +* In the 32-bit version of this macro, we store bp in a memory location +* because we've ran out of registers. +* Now we can't reference that memory location while we've modified +* %esp or %ebp, so we first push it on the stack, just before we push +* %ebp, and then when we need it we read it from the stack where we +* just pushed it. */ #define VMW_PORT_HB_OUT (cmd, in_ecx, in_si, in_di, \ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep outsb;" \ - "pop %%ebp;" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \
@@ -167,10 +174,12 @@ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep insb;" \ - "pop %%ebp" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \
Signature · 1 line
2.17.0
PATCH 2/3 drm/vmwgfx: Fix host logging / guestinfo reading error paths
The error paths were leaking opened channels. Fix by using dedicated error paths.
--- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 48 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 17 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +31 -17
@@ -329,8 +329,6 @@ int vmw_host_get_guestinfo(const char *guest_info_param,struct rpc_channel channel;char *msg, *reply =NULL ;size_t reply_len =0 ; -int ret =0 ; -if (!vmw_msg_enabled)return -ENODEV ;
@@ -344,15 +342,14 @@ int vmw_host_get_guestinfo(const char *guest_info_param,return -ENOMEM ; } -if (vmw_open_channel (&channel,RPCI_PROTOCOL_NUM ) || -vmw_send_msg (&channel, msg) || -vmw_recv_msg (&channel, (void *) &reply, &reply_len) || -vmw_close_channel (&channel)) { -DRM_ERROR ("Failed to get %s" , guest_info_param); +if (vmw_open_channel (&channel,RPCI_PROTOCOL_NUM )) + goto out_open; - ret = -EINVAL ; - } +if (vmw_send_msg (&channel, msg) || +vmw_recv_msg (&channel, (void *) &reply, &reply_len)) + goto out_msg; +vmw_close_channel (&channel);if (buffer && reply && reply_len >0 ) {/* Remove reply code, which are the first 2 characters of * the reply
@@ -369,7 +366,17 @@ int vmw_host_get_guestinfo(const char *guest_info_param,kfree (reply);kfree (msg); -return ret; +return 0 ; + +out_msg: +vmw_close_channel (&channel); +kfree (reply); +out_open: + *length =0 ; +kfree (msg); +DRM_ERROR ("Failed to get %s" , guest_info_param); + +return -EINVAL ; }
@@ -400,15 +407,22 @@ int vmw_host_log(const char *log)return -ENOMEM ; } -if (vmw_open_channel (&channel,RPCI_PROTOCOL_NUM ) || -vmw_send_msg (&channel, msg) || -vmw_close_channel (&channel)) { -DRM_ERROR ("Failed to send log\n" ); +if (vmw_open_channel (&channel,RPCI_PROTOCOL_NUM )) + goto out_open; - ret = -EINVAL ; - } +if (vmw_send_msg (&channel, msg)) + goto out_msg; +vmw_close_channel (&channel);kfree (msg); -return ret; +return 0 ; + +out_msg: +vmw_close_channel (&channel); +out_open: +kfree (msg); +DRM_ERROR ("Failed to send log\n" ); + +return -EINVAL ; }
Signature · 1 line
2.17.0
PATCH 3/3 drm/vmwgfx: Schedule an fb dirty update after resume
In reply to Thomas HellstromWe have had problems displaying fbdev after a resume and as a workaround we have had to call vmw_fb_refresh(). This has had a number of unwanted side-effects. The root of the problem was, however that the coalesced fbdev dirty region was not empty on the first dirty_mark() after a resume, so a flush was never scheduled.
Fix this by force scheduling an fbdev flush after resume, and remove the workaround.
--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 5 ----- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 22 +++++++--------------- 3 files changed, 7 insertions(+), 21 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +0 -5
@@ -1278,8 +1278,6 @@ static void vmw_master_drop(struct drm_device *dev, dev_priv->active_master = &dev_priv->fbdev_master;ttm_lock_set_kill (&dev_priv->fbdev_master.lock, false,SIGTERM );ttm_vt_unlock (&dev_priv->fbdev_master.lock); - -vmw_fb_refresh (dev_priv); }/**
@@ -1483,7 +1481,6 @@ static int vmw_pm_freeze(struct device *kdev)vmw_kms_resume (dev);if (dev_priv->enable_fb)vmw_fb_on (dev_priv); -vmw_fb_refresh (dev_priv);return -EBUSY ; }
@@ -1523,8 +1520,6 @@ static int vmw_pm_restore(struct device *kdev)if (dev_priv->enable_fb)vmw_fb_on (dev_priv); -vmw_fb_refresh (dev_priv); -return 0 ; }
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +0 -1
@@ -910,7 +910,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv);int vmw_fb_close (struct vmw_private *dev_priv);int vmw_fb_off (struct vmw_private *vmw_priv);int vmw_fb_on (struct vmw_private *vmw_priv); -void vmw_fb_refresh (struct vmw_private *vmw_priv);/** * Kernel modesetting - vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +7 -15
@@ -866,21 +866,13 @@ int vmw_fb_on(struct vmw_private *vmw_priv)spin_lock_irqsave (&par->dirty.lock, flags); par->dirty.active = true;spin_unlock_irqrestore (&par->dirty.lock, flags); - -return 0 ; -} -/** -* vmw_fb_refresh - Refresh fb display -* -* @vmw_priv: Pointer to device private -* -* Call into kms to show the fbdev display(s). -*/ -void vmw_fb_refresh (struct vmw_private *vmw_priv) -{ -if (!vmw_priv->fb_info) -return ; +/* +* Need to reschedule a dirty update, because otherwise that's +* only done in dirty_mark() if the previous coalesced +* dirty region was empty. +*/ +schedule_delayed_work (&par->local_work,0 ); -vmw_fb_set_par (vmw_priv->fb_info); +return 0 ; }
Signature · 6 lines
2.17.0 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel