summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Xie <AlexBin.Xie@amd.com>2017-06-16 09:07:29 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-06-19 17:31:22 -0400
commit5ac55629d6b3fcde69f46aa772c6e83be0bdcbbf (patch)
tree8ed09ff14dd34aa048296aa3a32e92e749e12d34
parent99eea4df901907b9121ad1c726d86c352a5eaca5 (diff)
drm/amdgpu: Optimize mutex usage (v4)
In original function amdgpu_bo_list_get, the waiting for result->lock can be quite long while mutex bo_list_lock was holding. It can make other tasks waiting for bo_list_lock for long period. Secondly, this patch allows several tasks(readers of idr) to proceed at the same time. v2: use rcu and kref (Dave Airlie and Christian König) v3: update v1 commit message (Michel Dänzer) v4: rebase on upstream (Alex Deucher) Signed-off-by: Alex Xie <AlexBin.Xie@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c40
2 files changed, 30 insertions, 12 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 9f827aca90ee..12d61edb3597 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -869,6 +869,8 @@ struct amdgpu_fpriv {
struct amdgpu_bo_list {
struct mutex lock;
+ struct rcu_head rhead;
+ struct kref refcount;
struct amdgpu_bo *gds_obj;
struct amdgpu_bo *gws_obj;
struct amdgpu_bo *oa_obj;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 7b5c3bb2142e..f621ee115c98 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -41,6 +41,20 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev,
struct drm_amdgpu_bo_list_entry *info,
unsigned num_entries);
+static void amdgpu_bo_list_release_rcu(struct kref *ref)
+{
+ unsigned i;
+ struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list,
+ refcount);
+
+ for (i = 0; i < list->num_entries; ++i)
+ amdgpu_bo_unref(&list->array[i].robj);
+
+ mutex_destroy(&list->lock);
+ kvfree(list->array);
+ kfree_rcu(list, rhead);
+}
+
static int amdgpu_bo_list_create(struct amdgpu_device *adev,
struct drm_file *filp,
struct drm_amdgpu_bo_list_entry *info,
@@ -57,7 +71,7 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev,
/* initialize bo list*/
mutex_init(&list->lock);
-
+ kref_init(&list->refcount);
r = amdgpu_bo_list_set(adev, filp, list, info, num_entries);
if (r) {
kfree(list);
@@ -83,14 +97,9 @@ static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id)
mutex_lock(&fpriv->bo_list_lock);
list = idr_remove(&fpriv->bo_list_handles, id);
- if (list) {
- /* Another user may have a reference to this list still */
- mutex_lock(&list->lock);
- mutex_unlock(&list->lock);
- amdgpu_bo_list_free(list);
- }
-
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,
@@ -185,11 +194,17 @@ amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id)
{
struct amdgpu_bo_list *result;
- mutex_lock(&fpriv->bo_list_lock);
+ rcu_read_lock();
result = idr_find(&fpriv->bo_list_handles, id);
- if (result)
- mutex_lock(&result->lock);
- mutex_unlock(&fpriv->bo_list_lock);
+
+ if (result) {
+ if (kref_get_unless_zero(&result->refcount))
+ mutex_lock(&result->lock);
+ else
+ result = NULL;
+ }
+ rcu_read_unlock();
+
return result;
}
@@ -227,6 +242,7 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list,
void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
{
mutex_unlock(&list->lock);
+ kref_put(&list->refcount, amdgpu_bo_list_release_rcu);
}
void amdgpu_bo_list_free(struct amdgpu_bo_list *list)