diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2015-10-21 17:12:49 +0200 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2015-10-21 21:27:59 +0200 |
commit | 59fcc976263f924f3f8cfeedeb1fcc133c3075ec (patch) | |
tree | 7ff8a9bb87d18c9b35852d0ba135636c2bc32acf | |
parent | 11462f02edbb123d1967b8138bf2006ec0189f89 (diff) |
vmwgfx: Stabilize the command buffer submission code
This commit addresses some stability problems with the command buffer
submission code recently introduced:
1) Make the vmw_cmdbuf_man_process() function handle reruns internally to
avoid losing interrupts if the caller forgets to rerun on -EAGAIN.
2) Handle default command buffer allocations using inline command buffers.
This avoids rare allocation deadlocks.
3) In case of command buffer errors we might lose fence submissions.
Therefore send a new fence after each command buffer error. This will help
avoid lengthy fence waits.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r-- | vmwgfx_cmdbuf.c | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/vmwgfx_cmdbuf.c b/vmwgfx_cmdbuf.c index c1cbc1c..dc3f6b7 100644 --- a/vmwgfx_cmdbuf.c +++ b/vmwgfx_cmdbuf.c @@ -414,16 +414,16 @@ static void vmw_cmdbuf_ctx_process(struct vmw_cmdbuf_man *man, * * Calls vmw_cmdbuf_ctx_process() on all contexts. If any context has * command buffers left that are not submitted to hardware, Make sure - * IRQ handling is turned on. Otherwise, make sure it's turned off. This - * function may return -EAGAIN to indicate it should be rerun due to - * possibly missed IRQs if IRQs has just been turned on. + * IRQ handling is turned on. Otherwise, make sure it's turned off. */ -static int vmw_cmdbuf_man_process(struct vmw_cmdbuf_man *man) +static void vmw_cmdbuf_man_process(struct vmw_cmdbuf_man *man) { - int notempty = 0; + int notempty; struct vmw_cmdbuf_context *ctx; int i; +retry: + notempty = 0; for_each_cmdbuf_ctx(man, i, ctx) vmw_cmdbuf_ctx_process(man, ctx, ¬empty); @@ -439,10 +439,8 @@ static int vmw_cmdbuf_man_process(struct vmw_cmdbuf_man *man) man->irq_on = true; /* Rerun in case we just missed an irq. */ - return -EAGAIN; + goto retry; } - - return 0; } /** @@ -467,8 +465,7 @@ static void vmw_cmdbuf_ctx_add(struct vmw_cmdbuf_man *man, header->cb_context = cb_context; list_add_tail(&header->list, &man->ctx[cb_context].submitted); - if (vmw_cmdbuf_man_process(man) == -EAGAIN) - vmw_cmdbuf_man_process(man); + vmw_cmdbuf_man_process(man); } /** @@ -487,8 +484,7 @@ static void vmw_cmdbuf_man_tasklet(unsigned long data) struct vmw_cmdbuf_man *man = (struct vmw_cmdbuf_man *) data; spin_lock(&man->lock); - if (vmw_cmdbuf_man_process(man) == -EAGAIN) - (void) vmw_cmdbuf_man_process(man); + vmw_cmdbuf_man_process(man); spin_unlock(&man->lock); } @@ -506,6 +502,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) struct vmw_cmdbuf_man *man = container_of(work, struct vmw_cmdbuf_man, work); struct vmw_cmdbuf_header *entry, *next; + uint32_t dummy; bool restart = false; spin_lock_bh(&man->lock); @@ -522,6 +519,8 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) if (restart && vmw_cmdbuf_startstop(man, true)) DRM_ERROR("Failed restarting command buffer context 0.\n"); + /* Send a new fence in case one was removed */ + vmw_fifo_send_fence(man->dev_priv, &dummy); } /** @@ -683,7 +682,7 @@ retry: spin_lock_bh(&man->lock); info->node = drm_mm_search_free(&man->mm, info->page_size, 0, 0); if (!info->node) { - (void) vmw_cmdbuf_man_process(man); + vmw_cmdbuf_man_process(man); info->node = drm_mm_search_free(&man->mm, info->page_size, 0, 0); if (!info->node) @@ -1187,7 +1186,14 @@ int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man, goto out_no_mm; man->has_pool = true; - man->default_size = default_size; + + /* + * For now, set the default size to VMW_CMDBUF_INLINE_SIZE to + * prevent deadlocks from happening when vmw_cmdbuf_space_pool() + * needs to wait for space and we block on further command + * submissions to be able to free up space. + */ + man->default_size = VMW_CMDBUF_INLINE_SIZE; DRM_INFO("Using command buffers with %s pool.\n", (man->using_mob) ? "MOB" : "DMA"); |