diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2015-09-29 09:35:28 -0700 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2015-09-30 05:44:54 -0700 |
commit | 067509f58dc84d412cff438e2f9c5f3bece15307 (patch) | |
tree | b906755e4f51035897893c02092a0d1e8f322109 | |
parent | 5c0d01dc41af4d1244a531df72e45a875ce064f2 (diff) |
vmwgfx: Crossport Fix a command submission hang regression
Crossported from upstream:
When we're out of command buffer space, we turn on the command buffer
processed irq without re-checking for finished command buffers afterwards.
This might lead to a missed irq and the command submission process waiting
forever for space.
Fix this by rerunning the command buffer submission handler whenever we're
out of command space. This ensures both that we don't needlessly turn on
the irq, and that if we decide to turn on the irq, we recheck for finished
command buffers before going to sleep.
Reported-and-tested-by: Bryan Li <ldexin@vmware.com>
In addition this commit makes sure we retry space allocation if it fails
due to a failing atomic kmalloc.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r-- | vmwgfx_cmdbuf.c | 24 | ||||
-rw-r--r-- | vmwgfx_execbuf.c | 4 |
2 files changed, 22 insertions, 6 deletions
diff --git a/vmwgfx_cmdbuf.c b/vmwgfx_cmdbuf.c index 2bdee50..c1cbc1c 100644 --- a/vmwgfx_cmdbuf.c +++ b/vmwgfx_cmdbuf.c @@ -674,6 +674,7 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, if (info->node) return true; +retry: ret = drm_mm_pre_get(&man->mm); if (ret) { info->ret = ret; @@ -681,10 +682,25 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, } spin_lock_bh(&man->lock); info->node = drm_mm_search_free(&man->mm, info->page_size, 0, 0); - if (info->node) - info->node = drm_mm_get_block_generic(info->node, - info->page_size, - 0, 1); + if (!info->node) { + (void) vmw_cmdbuf_man_process(man); + info->node = drm_mm_search_free(&man->mm, info->page_size, + 0, 0); + if (!info->node) + goto out_unlock; + } + + info->node = drm_mm_get_block_generic(info->node, + info->page_size, + 0, 1); + + /* Atomic kmalloc failed? Preload and retry.*/ + if (!info->node) { + spin_unlock_bh(&man->lock); + goto retry; + } + +out_unlock: spin_unlock_bh(&man->lock); return !!info->node; diff --git a/vmwgfx_execbuf.c b/vmwgfx_execbuf.c index a29dd70..a591691 100644 --- a/vmwgfx_execbuf.c +++ b/vmwgfx_execbuf.c @@ -3852,8 +3852,8 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, if (IS_ERR(kernel_commands)) return kernel_commands; - ret = copy_from_user(kernel_commands, user_commands, - command_size); + ret = __copy_from_user_nocache(kernel_commands, user_commands, + command_size); if (ret) { DRM_ERROR("Failed copying commands.\n"); vmw_cmdbuf_header_free(*header); |