diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2015-06-26 14:46:52 +0300 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2015-08-05 15:01:09 +0300 |
commit | 9b590783b3d6d2e06516788d1061176109677409 (patch) | |
tree | fd9757f581f2333701b1e99db3da8e78dc97ff6c /drivers/gpu/drm/vmwgfx | |
parent | 6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87 (diff) | |
download | linux-9b590783b3d6d2e06516788d1061176109677409.tar.xz |
drm/vmwgfx: Avoid cmdbuf alloc sleeping if !TASK_RUNNING
If the command buffer pool is out of space, the code waits until space is
available. However since the condition code tries to allocate a range manager
node while !TASK_RUNNING we get a kernel warning.
Avoid this by pre-allocating the mm node. This will also probably be more
efficient.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 83 |
1 files changed, 34 insertions, 49 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index b044bf530974..e94feb338f89 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -33,7 +33,8 @@ * multiple of the DMA pool allocation size. */ #define VMW_CMDBUF_INLINE_ALIGN 64 -#define VMW_CMDBUF_INLINE_SIZE (1024 - VMW_CMDBUF_INLINE_ALIGN) +#define VMW_CMDBUF_INLINE_SIZE \ + (1024 - ALIGN(sizeof(SVGACBHeader), VMW_CMDBUF_INLINE_ALIGN)) /** * struct vmw_cmdbuf_context - Command buffer context queues @@ -145,7 +146,7 @@ struct vmw_cmdbuf_header { SVGACBHeader *cb_header; SVGACBContext cb_context; struct list_head list; - struct drm_mm_node *node; + struct drm_mm_node node; dma_addr_t handle; u8 *cmd; size_t size; @@ -169,13 +170,13 @@ struct vmw_cmdbuf_dheader { * struct vmw_cmdbuf_alloc_info - Command buffer space allocation metadata * * @page_size: Size of requested command buffer space in pages. - * @node: The range manager node if allocation succeeded. - * @ret: Error code if failure. Otherwise 0. + * @node: Pointer to the range manager node. + * @done: True if this allocation has succeeded. */ struct vmw_cmdbuf_alloc_info { size_t page_size; struct drm_mm_node *node; - int ret; + bool done; }; /* Loop over each context in the command buffer manager. */ @@ -253,9 +254,7 @@ static void __vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) return; } - drm_mm_remove_node(header->node); - kfree(header->node); - header->node = NULL; + drm_mm_remove_node(&header->node); wake_up_all(&man->alloc_queue); if (header->cb_header) dma_pool_free(man->headers, header->cb_header, @@ -669,32 +668,26 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, { int ret; - if (info->node) + if (info->done) return true; - - info->node = kzalloc(sizeof(*info->node), GFP_KERNEL); - if (!info->node) { - info->ret = -ENOMEM; - return true; - } - + + memset(info->node, 0, sizeof(*info->node)); spin_lock_bh(&man->lock); - ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, 0, 0, + ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, + 0, 0, DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT); spin_unlock_bh(&man->lock); - if (ret) { - kfree(info->node); - info->node = NULL; - } + info->done = !ret; - return !!info->node; + return info->done; } /** * vmw_cmdbuf_alloc_space - Allocate buffer space from the main pool. * * @man: The command buffer manager. + * @node: Pointer to pre-allocated range-manager node. * @size: The size of the allocation. * @interruptible: Whether to sleep interruptible while waiting for space. * @@ -702,15 +695,16 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, * no space available ATM, it turns on IRQ handling and sleeps waiting for it to * become available. */ -static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, - size_t size, - bool interruptible) +int vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, + struct drm_mm_node *node, + size_t size, + bool interruptible) { struct vmw_cmdbuf_alloc_info info; info.page_size = PAGE_ALIGN(size) >> PAGE_SHIFT; - info.node = NULL; - info.ret = 0; + info.node = node; + info.done = false; /* * To prevent starvation of large requests, only one allocating call @@ -718,22 +712,14 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, */ if (interruptible) { if (mutex_lock_interruptible(&man->space_mutex)) - return ERR_PTR(-ERESTARTSYS); + return -ERESTARTSYS; } else { mutex_lock(&man->space_mutex); } /* Try to allocate space without waiting. */ - (void) vmw_cmdbuf_try_alloc(man, &info); - if (info.ret && !info.node) { - mutex_unlock(&man->space_mutex); - return ERR_PTR(info.ret); - } - - if (info.node) { - mutex_unlock(&man->space_mutex); - return info.node; - } + if (vmw_cmdbuf_try_alloc(man, &info)) + goto out_unlock; vmw_generic_waiter_add(man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, @@ -749,7 +735,7 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, (man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, &man->dev_priv->cmdbuf_waiters); mutex_unlock(&man->space_mutex); - return ERR_PTR(ret); + return ret; } } else { wait_event(man->alloc_queue, vmw_cmdbuf_try_alloc(man, &info)); @@ -757,11 +743,11 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, &man->dev_priv->cmdbuf_waiters); + +out_unlock: mutex_unlock(&man->space_mutex); - if (info.ret && !info.node) - return ERR_PTR(info.ret); - return info.node; + return 0; } /** @@ -785,10 +771,10 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, if (!man->has_pool) return -ENOMEM; - header->node = vmw_cmdbuf_alloc_space(man, size, interruptible); + ret = vmw_cmdbuf_alloc_space(man, &header->node, size, interruptible); - if (IS_ERR(header->node)) - return PTR_ERR(header->node); + if (ret) + return ret; header->cb_header = dma_pool_alloc(man->headers, GFP_KERNEL, &header->handle); @@ -797,9 +783,9 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, goto out_no_cb_header; } - header->size = header->node->size << PAGE_SHIFT; + header->size = header->node.size << PAGE_SHIFT; cb_hdr = header->cb_header; - offset = header->node->start << PAGE_SHIFT; + offset = header->node.start << PAGE_SHIFT; header->cmd = man->map + offset; memset(cb_hdr, 0, sizeof(*cb_hdr)); if (man->using_mob) { @@ -814,9 +800,8 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, out_no_cb_header: spin_lock_bh(&man->lock); - drm_mm_remove_node(header->node); + drm_mm_remove_node(&header->node); spin_unlock_bh(&man->lock); - kfree(header->node); return ret; } |