drm/vmwgfx: Refactor resource validation hashtable to use linux/hashtable implementation.

Vmwgfx's hashtab implementation needs to be replaced with linux/hashtable
to reduce maintenence burden.
As part of this effort, refactor the res_ht hashtable used for resource
validation during execbuf execution to use linux/hashtable implementation.
This also refactors vmw_validation_context to use vmw_sw_context as the
container for the hashtable, whereas before it used a vmwgfx_open_hash
directly. This makes vmw_validation_context less generic, but there is
no functional change since res_ht is the only instance where validation
context used a hashtable in vmwgfx driver.

Signed-off-by: Maaz Mombasawala <mombasawalam@vmware.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Zack Rusin <zackr@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-6-zack@kde.org
This commit is contained in:
Maaz Mombasawala 2022-10-22 00:02:24 -04:00 committed by Zack Rusin
parent 931e09d8d5
commit 9e931f2e09
5 changed files with 58 additions and 66 deletions

View file

@ -830,6 +830,22 @@ static void vmw_write_driver_id(struct vmw_private *dev)
} }
} }
static void vmw_sw_context_init(struct vmw_private *dev_priv)
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
hash_init(sw_context->res_ht);
}
static void vmw_sw_context_fini(struct vmw_private *dev_priv)
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
vfree(sw_context->cmd_bounce);
if (sw_context->staged_bindings)
vmw_binding_state_free(sw_context->staged_bindings);
}
static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
{ {
int ret; int ret;
@ -839,6 +855,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->drm.dev_private = dev_priv; dev_priv->drm.dev_private = dev_priv;
vmw_sw_context_init(dev_priv);
mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->cmdbuf_mutex);
mutex_init(&dev_priv->binding_mutex); mutex_init(&dev_priv->binding_mutex);
spin_lock_init(&dev_priv->resource_lock); spin_lock_init(&dev_priv->resource_lock);
@ -1168,9 +1186,7 @@ static void vmw_driver_unload(struct drm_device *dev)
unregister_pm_notifier(&dev_priv->pm_nb); unregister_pm_notifier(&dev_priv->pm_nb);
if (dev_priv->ctx.res_ht_initialized) vmw_sw_context_fini(dev_priv);
vmwgfx_ht_remove(&dev_priv->ctx.res_ht);
vfree(dev_priv->ctx.cmd_bounce);
if (dev_priv->enable_fb) { if (dev_priv->enable_fb) {
vmw_fb_off(dev_priv); vmw_fb_off(dev_priv);
vmw_fb_close(dev_priv); vmw_fb_close(dev_priv);
@ -1198,8 +1214,6 @@ static void vmw_driver_unload(struct drm_device *dev)
vmw_irq_uninstall(&dev_priv->drm); vmw_irq_uninstall(&dev_priv->drm);
ttm_object_device_release(&dev_priv->tdev); ttm_object_device_release(&dev_priv->tdev);
if (dev_priv->ctx.staged_bindings)
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
for (i = vmw_res_context; i < vmw_res_max; ++i) for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]); idr_destroy(&dev_priv->res_idr[i]);

View file

@ -30,6 +30,7 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/sync_file.h> #include <linux/sync_file.h>
#include <linux/hashtable.h>
#include <drm/drm_auth.h> #include <drm/drm_auth.h>
#include <drm/drm_device.h> #include <drm/drm_device.h>
@ -93,6 +94,7 @@
#define VMW_RES_STREAM ttm_driver_type2 #define VMW_RES_STREAM ttm_driver_type2
#define VMW_RES_FENCE ttm_driver_type3 #define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4 #define VMW_RES_SHADER ttm_driver_type4
#define VMW_RES_HT_ORDER 12
#define MKSSTAT_CAPACITY_LOG2 5U #define MKSSTAT_CAPACITY_LOG2 5U
#define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)
@ -425,8 +427,7 @@ struct vmw_ctx_validation_info;
* @ctx: The validation context * @ctx: The validation context
*/ */
struct vmw_sw_context{ struct vmw_sw_context{
struct vmwgfx_open_hash res_ht; DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER);
bool res_ht_initialized;
bool kernel; bool kernel;
struct vmw_fpriv *fp; struct vmw_fpriv *fp;
struct drm_file *filp; struct drm_file *filp;

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT // SPDX-License-Identifier: GPL-2.0 OR MIT
/************************************************************************** /**************************************************************************
* *
* Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
@ -25,6 +25,7 @@
* *
**************************************************************************/ **************************************************************************/
#include <linux/sync_file.h> #include <linux/sync_file.h>
#include <linux/hashtable.h>
#include "vmwgfx_drv.h" #include "vmwgfx_drv.h"
#include "vmwgfx_reg.h" #include "vmwgfx_reg.h"
@ -34,7 +35,6 @@
#include "vmwgfx_binding.h" #include "vmwgfx_binding.h"
#include "vmwgfx_mksstat.h" #include "vmwgfx_mksstat.h"
#define VMW_RES_HT_ORDER 12
/* /*
* Helper macro to get dx_ctx_node if available otherwise print an error * Helper macro to get dx_ctx_node if available otherwise print an error
@ -4101,7 +4101,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
int ret; int ret;
int32_t out_fence_fd = -1; int32_t out_fence_fd = -1;
struct sync_file *sync_file = NULL; struct sync_file *sync_file = NULL;
DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1); DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) { if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
out_fence_fd = get_unused_fd_flags(O_CLOEXEC); out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
@ -4164,14 +4164,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (sw_context->staged_bindings) if (sw_context->staged_bindings)
vmw_binding_state_reset(sw_context->staged_bindings); vmw_binding_state_reset(sw_context->staged_bindings);
if (!sw_context->res_ht_initialized) {
ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
if (unlikely(ret != 0))
goto out_unlock;
sw_context->res_ht_initialized = true;
}
INIT_LIST_HEAD(&sw_context->staged_cmd_res); INIT_LIST_HEAD(&sw_context->staged_cmd_res);
sw_context->ctx = &val_ctx; sw_context->ctx = &val_ctx;
ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle); ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT // SPDX-License-Identifier: GPL-2.0 OR MIT
/************************************************************************** /**************************************************************************
* *
* Copyright © 2018 VMware, Inc., Palo Alto, CA., USA * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
@ -180,11 +180,16 @@ vmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
if (!ctx->merge_dups) if (!ctx->merge_dups)
return NULL; return NULL;
if (ctx->ht) { if (ctx->sw_context) {
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
unsigned long key = (unsigned long) vbo;
if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash)) hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
bo_node = container_of(hash, typeof(*bo_node), hash); if (hash->key == key) {
bo_node = container_of(hash, typeof(*bo_node), hash);
break;
}
}
} else { } else {
struct vmw_validation_bo_node *entry; struct vmw_validation_bo_node *entry;
@ -217,11 +222,16 @@ vmw_validation_find_res_dup(struct vmw_validation_context *ctx,
if (!ctx->merge_dups) if (!ctx->merge_dups)
return NULL; return NULL;
if (ctx->ht) { if (ctx->sw_context) {
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
unsigned long key = (unsigned long) res;
if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash)) hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
res_node = container_of(hash, typeof(*res_node), hash); if (hash->key == key) {
res_node = container_of(hash, typeof(*res_node), hash);
break;
}
}
} else { } else {
struct vmw_validation_res_node *entry; struct vmw_validation_res_node *entry;
@ -269,20 +279,15 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx,
} }
} else { } else {
struct ttm_validate_buffer *val_buf; struct ttm_validate_buffer *val_buf;
int ret;
bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node)); bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
if (!bo_node) if (!bo_node)
return -ENOMEM; return -ENOMEM;
if (ctx->ht) { if (ctx->sw_context) {
bo_node->hash.key = (unsigned long) vbo; bo_node->hash.key = (unsigned long) vbo;
ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash); hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head,
if (ret) { bo_node->hash.key);
DRM_ERROR("Failed to initialize a buffer "
"validation entry.\n");
return ret;
}
} }
val_buf = &bo_node->base; val_buf = &bo_node->base;
val_buf->bo = ttm_bo_get_unless_zero(&vbo->base); val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
@ -316,7 +321,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
bool *first_usage) bool *first_usage)
{ {
struct vmw_validation_res_node *node; struct vmw_validation_res_node *node;
int ret;
node = vmw_validation_find_res_dup(ctx, res); node = vmw_validation_find_res_dup(ctx, res);
if (node) { if (node) {
@ -330,14 +334,9 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
return -ENOMEM; return -ENOMEM;
} }
if (ctx->ht) { if (ctx->sw_context) {
node->hash.key = (unsigned long) res; node->hash.key = (unsigned long) res;
ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash); hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key);
if (ret) {
DRM_ERROR("Failed to initialize a resource validation "
"entry.\n");
return ret;
}
} }
node->res = vmw_resource_reference_unless_doomed(res); node->res = vmw_resource_reference_unless_doomed(res);
if (!node->res) if (!node->res)
@ -681,19 +680,19 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx)
struct vmw_validation_bo_node *entry; struct vmw_validation_bo_node *entry;
struct vmw_validation_res_node *val; struct vmw_validation_res_node *val;
if (!ctx->ht) if (!ctx->sw_context)
return; return;
list_for_each_entry(entry, &ctx->bo_list, base.head) list_for_each_entry(entry, &ctx->bo_list, base.head)
(void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash); hash_del_rcu(&entry->hash.head);
list_for_each_entry(val, &ctx->resource_list, head) list_for_each_entry(val, &ctx->resource_list, head)
(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); hash_del_rcu(&val->hash.head);
list_for_each_entry(val, &ctx->resource_ctx_list, head) list_for_each_entry(val, &ctx->resource_ctx_list, head)
(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); hash_del_rcu(&entry->hash.head);
ctx->ht = NULL; ctx->sw_context = NULL;
} }
/** /**

View file

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /* SPDX-License-Identifier: GPL-2.0 OR MIT */
/************************************************************************** /**************************************************************************
* *
* Copyright © 2018 VMware, Inc., Palo Alto, CA., USA * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
@ -29,12 +29,11 @@
#define _VMWGFX_VALIDATION_H_ #define _VMWGFX_VALIDATION_H_
#include <linux/list.h> #include <linux/list.h>
#include <linux/hashtable.h>
#include <linux/ww_mutex.h> #include <linux/ww_mutex.h>
#include <drm/ttm/ttm_execbuf_util.h> #include <drm/ttm/ttm_execbuf_util.h>
#include "vmwgfx_hashtab.h"
#define VMW_RES_DIRTY_NONE 0 #define VMW_RES_DIRTY_NONE 0
#define VMW_RES_DIRTY_SET BIT(0) #define VMW_RES_DIRTY_SET BIT(0)
#define VMW_RES_DIRTY_CLEAR BIT(1) #define VMW_RES_DIRTY_CLEAR BIT(1)
@ -59,7 +58,7 @@
* @total_mem: Amount of reserved memory. * @total_mem: Amount of reserved memory.
*/ */
struct vmw_validation_context { struct vmw_validation_context {
struct vmwgfx_open_hash *ht; struct vmw_sw_context *sw_context;
struct list_head resource_list; struct list_head resource_list;
struct list_head resource_ctx_list; struct list_head resource_ctx_list;
struct list_head bo_list; struct list_head bo_list;
@ -82,16 +81,16 @@ struct vmw_fence_obj;
/** /**
* DECLARE_VAL_CONTEXT - Declare a validation context with initialization * DECLARE_VAL_CONTEXT - Declare a validation context with initialization
* @_name: The name of the variable * @_name: The name of the variable
* @_ht: The hash table used to find dups or NULL if none * @_sw_context: Contains the hash table used to find dups or NULL if none
* @_merge_dups: Whether to merge duplicate buffer object- or resource * @_merge_dups: Whether to merge duplicate buffer object- or resource
* entries. If set to true, ideally a hash table pointer should be supplied * entries. If set to true, ideally a hash table pointer should be supplied
* as well unless the number of resources and buffer objects per validation * as well unless the number of resources and buffer objects per validation
* is known to be very small * is known to be very small
*/ */
#endif #endif
#define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups) \ #define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups) \
struct vmw_validation_context _name = \ struct vmw_validation_context _name = \
{ .ht = _ht, \ { .sw_context = _sw_context, \
.resource_list = LIST_HEAD_INIT((_name).resource_list), \ .resource_list = LIST_HEAD_INIT((_name).resource_list), \
.resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \ .resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \
.bo_list = LIST_HEAD_INIT((_name).bo_list), \ .bo_list = LIST_HEAD_INIT((_name).bo_list), \
@ -114,19 +113,6 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx)
return !list_empty(&ctx->bo_list); return !list_empty(&ctx->bo_list);
} }
/**
* vmw_validation_set_ht - Register a hash table for duplicate finding
* @ctx: The validation context
* @ht: Pointer to a hash table to use for duplicate finding
* This function is intended to be used if the hash table wasn't
* available at validation context declaration time
*/
static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx,
struct vmwgfx_open_hash *ht)
{
ctx->ht = ht;
}
/** /**
* vmw_validation_bo_reserve - Reserve buffer objects registered with a * vmw_validation_bo_reserve - Reserve buffer objects registered with a
* validation context * validation context