diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2012-11-06 06:31:50 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-11-20 01:15:05 -0500 |
commit | cdad05216c2b2edfe92a9f87d6ae51aab277f3b2 (patch) | |
tree | 1ba899709b77745acec655d0a8eea3f08c97a885 | |
parent | 4b20db3de8dab005b07c74161cb041db8c5ff3a7 (diff) |
drm/ttm, drm/vmwgfx: Use RCU locking for object lookups v3
The mostly used lookup+get put+potential_destroy path of TTM objects
is converted to use RCU locks. This will substantially decrease the amount
of locked bus cycles during normal operation.
Since we use kfree_rcu to free the objects, no rcu synchronization is needed
at module unload time.
v2: Don't touch include/linux/kref.h
v3: Adapt to kref_get_unless_zero return value change
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_object.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 8 | ||||
-rw-r--r-- | include/drm/ttm/ttm_object.h | 4 |
3 files changed, 19 insertions, 23 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index c7857874956a..f18eeb458139 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c | |||
@@ -80,7 +80,7 @@ struct ttm_object_file { | |||
80 | */ | 80 | */ |
81 | 81 | ||
82 | struct ttm_object_device { | 82 | struct ttm_object_device { |
83 | rwlock_t object_lock; | 83 | spinlock_t object_lock; |
84 | struct drm_open_hash object_hash; | 84 | struct drm_open_hash object_hash; |
85 | atomic_t object_count; | 85 | atomic_t object_count; |
86 | struct ttm_mem_global *mem_glob; | 86 | struct ttm_mem_global *mem_glob; |
@@ -157,12 +157,12 @@ int ttm_base_object_init(struct ttm_object_file *tfile, | |||
157 | base->refcount_release = refcount_release; | 157 | base->refcount_release = refcount_release; |
158 | base->ref_obj_release = ref_obj_release; | 158 | base->ref_obj_release = ref_obj_release; |
159 | base->object_type = object_type; | 159 | base->object_type = object_type; |
160 | write_lock(&tdev->object_lock); | 160 | spin_lock(&tdev->object_lock); |
161 | kref_init(&base->refcount); | 161 | kref_init(&base->refcount); |
162 | ret = drm_ht_just_insert_please(&tdev->object_hash, | 162 | ret = drm_ht_just_insert_please(&tdev->object_hash, |
163 | &base->hash, | 163 | &base->hash, |
164 | (unsigned long)base, 31, 0, 0); | 164 | (unsigned long)base, 31, 0, 0); |
165 | write_unlock(&tdev->object_lock); | 165 | spin_unlock(&tdev->object_lock); |
166 | if (unlikely(ret != 0)) | 166 | if (unlikely(ret != 0)) |
167 | goto out_err0; | 167 | goto out_err0; |
168 | 168 | ||
@@ -186,30 +186,22 @@ static void ttm_release_base(struct kref *kref) | |||
186 | container_of(kref, struct ttm_base_object, refcount); | 186 | container_of(kref, struct ttm_base_object, refcount); |
187 | struct ttm_object_device *tdev = base->tfile->tdev; | 187 | struct ttm_object_device *tdev = base->tfile->tdev; |
188 | 188 | ||
189 | spin_lock(&tdev->object_lock); | ||
189 | (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); | 190 | (void)drm_ht_remove_item(&tdev->object_hash, &base->hash); |
190 | write_unlock(&tdev->object_lock); | 191 | spin_unlock(&tdev->object_lock); |
191 | if (base->refcount_release) { | 192 | if (base->refcount_release) { |
192 | ttm_object_file_unref(&base->tfile); | 193 | ttm_object_file_unref(&base->tfile); |
193 | base->refcount_release(&base); | 194 | base->refcount_release(&base); |
194 | } | 195 | } |
195 | write_lock(&tdev->object_lock); | ||
196 | } | 196 | } |
197 | 197 | ||
198 | void ttm_base_object_unref(struct ttm_base_object **p_base) | 198 | void ttm_base_object_unref(struct ttm_base_object **p_base) |
199 | { | 199 | { |
200 | struct ttm_base_object *base = *p_base; | 200 | struct ttm_base_object *base = *p_base; |
201 | struct ttm_object_device *tdev = base->tfile->tdev; | ||
202 | 201 | ||
203 | *p_base = NULL; | 202 | *p_base = NULL; |
204 | 203 | ||
205 | /* | ||
206 | * Need to take the lock here to avoid racing with | ||
207 | * users trying to look up the object. | ||
208 | */ | ||
209 | |||
210 | write_lock(&tdev->object_lock); | ||
211 | kref_put(&base->refcount, ttm_release_base); | 204 | kref_put(&base->refcount, ttm_release_base); |
212 | write_unlock(&tdev->object_lock); | ||
213 | } | 205 | } |
214 | EXPORT_SYMBOL(ttm_base_object_unref); | 206 | EXPORT_SYMBOL(ttm_base_object_unref); |
215 | 207 | ||
@@ -221,14 +213,14 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, | |||
221 | struct drm_hash_item *hash; | 213 | struct drm_hash_item *hash; |
222 | int ret; | 214 | int ret; |
223 | 215 | ||
224 | read_lock(&tdev->object_lock); | 216 | rcu_read_lock(); |
225 | ret = drm_ht_find_item(&tdev->object_hash, key, &hash); | 217 | ret = drm_ht_find_item(&tdev->object_hash, key, &hash); |
226 | 218 | ||
227 | if (likely(ret == 0)) { | 219 | if (likely(ret == 0)) { |
228 | base = drm_hash_entry(hash, struct ttm_base_object, hash); | 220 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
229 | kref_get(&base->refcount); | 221 | ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL; |
230 | } | 222 | } |
231 | read_unlock(&tdev->object_lock); | 223 | rcu_read_unlock(); |
232 | 224 | ||
233 | if (unlikely(ret != 0)) | 225 | if (unlikely(ret != 0)) |
234 | return NULL; | 226 | return NULL; |
@@ -426,7 +418,7 @@ struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global | |||
426 | return NULL; | 418 | return NULL; |
427 | 419 | ||
428 | tdev->mem_glob = mem_glob; | 420 | tdev->mem_glob = mem_glob; |
429 | rwlock_init(&tdev->object_lock); | 421 | spin_lock_init(&tdev->object_lock); |
430 | atomic_set(&tdev->object_count, 0); | 422 | atomic_set(&tdev->object_count, 0); |
431 | ret = drm_ht_create(&tdev->object_hash, hash_order); | 423 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
432 | 424 | ||
@@ -444,9 +436,9 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev) | |||
444 | 436 | ||
445 | *p_tdev = NULL; | 437 | *p_tdev = NULL; |
446 | 438 | ||
447 | write_lock(&tdev->object_lock); | 439 | spin_lock(&tdev->object_lock); |
448 | drm_ht_remove(&tdev->object_hash); | 440 | drm_ht_remove(&tdev->object_hash); |
449 | write_unlock(&tdev->object_lock); | 441 | spin_unlock(&tdev->object_lock); |
450 | 442 | ||
451 | kfree(tdev); | 443 | kfree(tdev); |
452 | } | 444 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 596cef3c9189..292c988c54ea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -351,7 +351,7 @@ static void vmw_user_context_free(struct vmw_resource *res) | |||
351 | container_of(res, struct vmw_user_context, res); | 351 | container_of(res, struct vmw_user_context, res); |
352 | struct vmw_private *dev_priv = res->dev_priv; | 352 | struct vmw_private *dev_priv = res->dev_priv; |
353 | 353 | ||
354 | kfree(ctx); | 354 | ttm_base_object_kfree(ctx, base); |
355 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | 355 | ttm_mem_global_free(vmw_mem_glob(dev_priv), |
356 | vmw_user_context_size); | 356 | vmw_user_context_size); |
357 | } | 357 | } |
@@ -1143,7 +1143,7 @@ static void vmw_user_surface_free(struct vmw_resource *res) | |||
1143 | kfree(srf->offsets); | 1143 | kfree(srf->offsets); |
1144 | kfree(srf->sizes); | 1144 | kfree(srf->sizes); |
1145 | kfree(srf->snooper.image); | 1145 | kfree(srf->snooper.image); |
1146 | kfree(user_srf); | 1146 | ttm_base_object_kfree(user_srf, base); |
1147 | ttm_mem_global_free(vmw_mem_glob(dev_priv), size); | 1147 | ttm_mem_global_free(vmw_mem_glob(dev_priv), size); |
1148 | } | 1148 | } |
1149 | 1149 | ||
@@ -1571,7 +1571,7 @@ static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) | |||
1571 | { | 1571 | { |
1572 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); | 1572 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); |
1573 | 1573 | ||
1574 | kfree(vmw_user_bo); | 1574 | ttm_base_object_kfree(vmw_user_bo, base); |
1575 | } | 1575 | } |
1576 | 1576 | ||
1577 | static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) | 1577 | static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) |
@@ -1759,7 +1759,7 @@ static void vmw_user_stream_free(struct vmw_resource *res) | |||
1759 | container_of(res, struct vmw_user_stream, stream.res); | 1759 | container_of(res, struct vmw_user_stream, stream.res); |
1760 | struct vmw_private *dev_priv = res->dev_priv; | 1760 | struct vmw_private *dev_priv = res->dev_priv; |
1761 | 1761 | ||
1762 | kfree(stream); | 1762 | ttm_base_object_kfree(stream, base); |
1763 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | 1763 | ttm_mem_global_free(vmw_mem_glob(dev_priv), |
1764 | vmw_user_stream_size); | 1764 | vmw_user_stream_size); |
1765 | } | 1765 | } |
diff --git a/include/drm/ttm/ttm_object.h b/include/drm/ttm/ttm_object.h index b01c563b2751..fc0cf0649901 100644 --- a/include/drm/ttm/ttm_object.h +++ b/include/drm/ttm/ttm_object.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
41 | #include <drm/drm_hashtab.h> | 41 | #include <drm/drm_hashtab.h> |
42 | #include <linux/kref.h> | 42 | #include <linux/kref.h> |
43 | #include <linux/rcupdate.h> | ||
43 | #include <ttm/ttm_memory.h> | 44 | #include <ttm/ttm_memory.h> |
44 | 45 | ||
45 | /** | 46 | /** |
@@ -120,6 +121,7 @@ struct ttm_object_device; | |||
120 | */ | 121 | */ |
121 | 122 | ||
122 | struct ttm_base_object { | 123 | struct ttm_base_object { |
124 | struct rcu_head rhead; | ||
123 | struct drm_hash_item hash; | 125 | struct drm_hash_item hash; |
124 | enum ttm_object_type object_type; | 126 | enum ttm_object_type object_type; |
125 | bool shareable; | 127 | bool shareable; |
@@ -268,4 +270,6 @@ extern struct ttm_object_device *ttm_object_device_init | |||
268 | 270 | ||
269 | extern void ttm_object_device_release(struct ttm_object_device **p_tdev); | 271 | extern void ttm_object_device_release(struct ttm_object_device **p_tdev); |
270 | 272 | ||
273 | #define ttm_base_object_kfree(__object, __base)\ | ||
274 | kfree_rcu(__object, __base.rhead) | ||
271 | #endif | 275 | #endif |