diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2018-09-26 15:36:52 +0200 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2018-09-27 15:21:36 +0200 |
commit | fc18afcf5fb2d8776414076d81d907d8be82b362 (patch) | |
tree | 1811827715386353452ef6ab73460a77250aedca /drivers/gpu/drm/vmwgfx/vmwgfx_validation.c | |
parent | drm/vmwgfx: Use new validation interface for the modesetting code v2 (diff) | |
download | linux-dev-fc18afcf5fb2d8776414076d81d907d8be82b362.tar.xz linux-dev-fc18afcf5fb2d8776414076d81d907d8be82b362.zip |
drm/vmwgfx: Use a validation context allocator for relocations and validations
A common trait of these objects are that they are allocated during the
command validation phase and freed after command submission. Furthermore
they are accessed by a single thread only. So provide a simple unprotected
stack-like allocator from which these objects can be allocated. Their
memory is freed with the validation context when the command submission
is done.
Note that the mm subsystem maintains a per-cpu cache of single pages to
make single page allocation and freeing efficient.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_validation.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_validation.c | 92 |
1 files changed, 75 insertions, 17 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c index dbb58cce0987..3158fe161b2d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c @@ -80,6 +80,66 @@ struct vmw_validation_res_node { }; /** + * vmw_validation_mem_alloc - Allocate kernel memory from the validation + * context based allocator + * @ctx: The validation context + * @size: The number of bytes to allocated. + * + * The memory allocated may not exceed PAGE_SIZE, and the returned + * address is aligned to sizeof(long). All memory allocated this way is + * reclaimed after validation when calling any of the exported functions: + * vmw_validation_unref_lists() + * vmw_validation_revert() + * vmw_validation_done() + * + * Return: Pointer to the allocated memory on success. NULL on failure. + */ +void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, size_t size) +{ + void *addr; + + size = ALIGN(size, sizeof(long)); + if (size > PAGE_SIZE) + return NULL; + + if (ctx->mem_size_left < size) { + struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO); + + if (!page) + return NULL; + + list_add_tail(&page->lru, &ctx->page_list); + ctx->page_address = page_address(page); + ctx->mem_size_left = PAGE_SIZE; + } + + addr = (void *) (ctx->page_address + (PAGE_SIZE - ctx->mem_size_left)); + ctx->mem_size_left -= size; + + return addr; +} + +/** + * vmw_validation_mem_free - Free all memory allocated using + * vmw_validation_mem_alloc() + * @ctx: The validation context + * + * All memory previously allocated for this context using + * vmw_validation_mem_alloc() is freed. + */ +static void vmw_validation_mem_free(struct vmw_validation_context *ctx) +{ + struct page *entry, *next; + + list_for_each_entry_safe(entry, next, &ctx->page_list, lru) { + list_del_init(&entry->lru); + __free_page(entry); + } + + ctx->mem_size_left = 0; +} + +/** * vmw_validation_find_bo_dup - Find a duplicate buffer object entry in the * validation context's lists. * @ctx: The validation context to search. @@ -188,7 +248,7 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx, struct ttm_validate_buffer *val_buf; int ret; - bo_node = kmalloc(sizeof(*bo_node), GFP_KERNEL); + bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node)); if (!bo_node) return -ENOMEM; @@ -198,7 +258,6 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx, if (ret) { DRM_ERROR("Failed to initialize a buffer " "validation entry.\n"); - kfree(bo_node); return ret; } } @@ -238,7 +297,7 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx, goto out_fill; } - node = kzalloc(sizeof(*node) + priv_size, GFP_KERNEL); + node = vmw_validation_mem_alloc(ctx, sizeof(*node) + priv_size); if (!node) { DRM_ERROR("Failed to allocate a resource validation " "entry.\n"); @@ -251,7 +310,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx, if (ret) { DRM_ERROR("Failed to initialize a resource validation " "entry.\n"); - kfree(node); return ret; } } @@ -542,25 +600,24 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx) */ void vmw_validation_unref_lists(struct vmw_validation_context *ctx) { - struct vmw_validation_bo_node *entry, *next; - struct vmw_validation_res_node *val, *val_next; + struct vmw_validation_bo_node *entry; + struct vmw_validation_res_node *val; - list_for_each_entry_safe(entry, next, &ctx->bo_list, base.head) { - list_del(&entry->base.head); + list_for_each_entry(entry, &ctx->bo_list, base.head) ttm_bo_unref(&entry->base.bo); - kfree(entry); - } list_splice_init(&ctx->resource_ctx_list, &ctx->resource_list); - list_for_each_entry_safe(val, val_next, &ctx->resource_list, head) { - list_del(&val->head); + list_for_each_entry(val, &ctx->resource_list, head) vmw_resource_unreference(&val->res); - kfree(val); - } - WARN_ON(!list_empty(&ctx->bo_list)); - WARN_ON(!list_empty(&ctx->resource_list)); - WARN_ON(!list_empty(&ctx->resource_ctx_list)); + /* + * No need to detach each list entry since they are all freed with + * vmw_validation_free_mem. Just make the inaccessible. + */ + INIT_LIST_HEAD(&ctx->bo_list); + INIT_LIST_HEAD(&ctx->resource_list); + + vmw_validation_mem_free(ctx); } /** @@ -637,6 +694,7 @@ void vmw_validation_revert(struct vmw_validation_context *ctx) vmw_validation_res_unreserve(ctx, true); if (ctx->res_mutex) mutex_unlock(ctx->res_mutex); + vmw_validation_unref_lists(ctx); } /** |