This avoids multiple allocations for the head and the array. Signed-off-by: Christian König <christian.koenig at amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 114 +++++++++++----------------- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 17 +++-- 2 files changed, 57 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 096bcf4a6334..d472a2c8399f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -35,13 +35,15 @@ #define AMDGPU_BO_LIST_MAX_PRIORITY 32u #define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1) -static int amdgpu_bo_list_set(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_bo_list *list, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries); +static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu) +{ + struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list, + rhead); + + kvfree(list); +} -static void amdgpu_bo_list_release_rcu(struct kref *ref) +static void amdgpu_bo_list_free(struct kref *ref) { struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list, refcount); @@ -50,67 +52,36 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref) amdgpu_bo_list_for_each_entry(e, list) amdgpu_bo_unref(&e->robj); - kvfree(list->array); - kfree_rcu(list, rhead); + call_rcu(&list->rhead, amdgpu_bo_list_free_rcu); } -int amdgpu_bo_list_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries, - struct amdgpu_bo_list **list_out) +int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + unsigned num_entries, struct amdgpu_bo_list **result) { + unsigned last_entry = 0, first_userptr = num_entries; + struct amdgpu_bo_list_entry *array; struct amdgpu_bo_list *list; + uint64_t total_size = 0; + size_t size; + unsigned i; int r; + if (num_entries > SIZE_MAX / sizeof(struct amdgpu_bo_list_entry)) + return -EINVAL; - list = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL); + size = sizeof(struct amdgpu_bo_list); + size += num_entries * sizeof(struct amdgpu_bo_list_entry); + list = kvmalloc(size, GFP_KERNEL); if (!list) return -ENOMEM; - /* initialize bo list*/ kref_init(&list->refcount); - r = amdgpu_bo_list_set(adev, filp, list, info, num_entries); - if (r) { - kfree(list); - return r; - } - - *list_out = list; - return 0; -} - -static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) -{ - struct amdgpu_bo_list *list; - - mutex_lock(&fpriv->bo_list_lock); - list = idr_remove(&fpriv->bo_list_handles, id); - mutex_unlock(&fpriv->bo_list_lock); - if (list) - kref_put(&list->refcount, amdgpu_bo_list_release_rcu); -} - -static int amdgpu_bo_list_set(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_bo_list *list, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries) -{ - struct amdgpu_bo_list_entry *array; - struct amdgpu_bo *gds_obj = adev->gds.gds_gfx_bo; - struct amdgpu_bo *gws_obj = adev->gds.gws_gfx_bo; - struct amdgpu_bo *oa_obj = adev->gds.oa_gfx_bo; - - unsigned last_entry = 0, first_userptr = num_entries; - struct amdgpu_bo_list_entry *e; - uint64_t total_size = 0; - unsigned i; - int r; + list->gds_obj = adev->gds.gds_gfx_bo; + list->gws_obj = adev->gds.gws_gfx_bo; + list->oa_obj = adev->gds.oa_gfx_bo; - array = kvmalloc_array(num_entries, sizeof(struct amdgpu_bo_list_entry), GFP_KERNEL); - if (!array) - return -ENOMEM; + array = amdgpu_bo_list_array_entry(list, 0); memset(array, 0, num_entries * sizeof(struct amdgpu_bo_list_entry)); for (i = 0; i < num_entries; ++i) { @@ -147,36 +118,41 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, entry->tv.shared = !entry->robj->prime_shared_count; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_GDS) - gds_obj = entry->robj; + list->gds_obj = entry->robj; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_GWS) - gws_obj = entry->robj; + list->gws_obj = entry->robj; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_OA) - oa_obj = entry->robj; + list->oa_obj = entry->robj; total_size += amdgpu_bo_size(entry->robj); trace_amdgpu_bo_list_set(list, entry->robj); } - amdgpu_bo_list_for_each_entry(e, list) - amdgpu_bo_unref(&list->array[i].robj); - - kvfree(list->array); - - list->gds_obj = gds_obj; - list->gws_obj = gws_obj; - list->oa_obj = oa_obj; list->first_userptr = first_userptr; - list->array = array; list->num_entries = num_entries; trace_amdgpu_cs_bo_status(list->num_entries, total_size); + + *result = list; return 0; error_free: while (i--) amdgpu_bo_unref(&array[i].robj); - kvfree(array); + kvfree(list); return r; + +} + +static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) +{ + struct amdgpu_bo_list *list; + + mutex_lock(&fpriv->bo_list_lock); + list = idr_remove(&fpriv->bo_list_handles, id); + mutex_unlock(&fpriv->bo_list_lock); + if (list) + kref_put(&list->refcount, amdgpu_bo_list_free); } int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, @@ -229,7 +205,7 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, void amdgpu_bo_list_put(struct amdgpu_bo_list *list) { - kref_put(&list->refcount, amdgpu_bo_list_release_rcu); + kref_put(&list->refcount, amdgpu_bo_list_free); } int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 3d77abfcd4a6..61b089768e1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -48,7 +48,6 @@ struct amdgpu_bo_list { struct amdgpu_bo *oa_obj; unsigned first_userptr; unsigned num_entries; - struct amdgpu_bo_list_entry *array; }; int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, @@ -65,14 +64,22 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, unsigned num_entries, struct amdgpu_bo_list **list); +static inline struct amdgpu_bo_list_entry * +amdgpu_bo_list_array_entry(struct amdgpu_bo_list *list, unsigned index) +{ + struct amdgpu_bo_list_entry *array = (void *)&list[1]; + + return &array[index]; +} + #define amdgpu_bo_list_for_each_entry(e, list) \ - for (e = &(list)->array[0]; \ - e != &(list)->array[(list)->num_entries]; \ + for (e = amdgpu_bo_list_array_entry(list, 0); \ + e != amdgpu_bo_list_array_entry(list, (list)->num_entries); \ ++e) #define amdgpu_bo_list_for_each_userptr_entry(e, list) \ - for (e = &(list)->array[(list)->first_userptr]; \ - e != &(list)->array[(list)->num_entries]; \ + for (e = amdgpu_bo_list_array_entry(list, (list)->first_userptr); \ + e != amdgpu_bo_list_array_entry(list, (list)->num_entries); \ ++e) #endif -- 2.14.1