Rev 4075 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4075 | Rev 4569 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /************************************************************************** |
1 | /************************************************************************** |
2 | * |
2 | * |
3 | * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA |
3 | * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA |
4 | * All Rights Reserved. |
4 | * All Rights Reserved. |
5 | * |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the |
7 | * copy of this software and associated documentation files (the |
8 | * "Software"), to deal in the Software without restriction, including |
8 | * "Software"), to deal in the Software without restriction, including |
Line 24... | Line 24... | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
25 | * |
25 | * |
26 | **************************************************************************/ |
26 | **************************************************************************/ |
27 | /* |
27 | /* |
28 | * Authors: Thomas Hellstrom |
28 | * Authors: Thomas Hellstrom |
- | 29 | * |
|
- | 30 | * While no substantial code is shared, the prime code is inspired by |
|
- | 31 | * drm_prime.c, with |
|
- | 32 | * Authors: |
|
- | 33 | * Dave Airlie |
|
- | 34 | * Rob Clark |
|
29 | */ |
35 | */ |
30 | /** @file ttm_ref_object.c |
36 | /** @file ttm_ref_object.c |
31 | * |
37 | * |
32 | * Base- and reference object implementation for the various |
38 | * Base- and reference object implementation for the various |
33 | * ttm objects. Implements reference counting, minimal security checks |
39 | * ttm objects. Implements reference counting, minimal security checks |
34 | * and release on file close. |
40 | * and release on file close. |
35 | */ |
41 | */ |
Line -... | Line 42... | ||
- | 42 | ||
36 | 43 | ||
37 | /** |
44 | /** |
38 | * struct ttm_object_file |
45 | * struct ttm_object_file |
39 | * |
46 | * |
40 | * @tdev: Pointer to the ttm_object_device. |
47 | * @tdev: Pointer to the ttm_object_device. |
Line 49... | Line 56... | ||
49 | * for fast lookup of ref objects given a base object. |
56 | * for fast lookup of ref objects given a base object. |
50 | */ |
57 | */ |
Line 51... | Line 58... | ||
51 | 58 | ||
Line -... | Line 59... | ||
- | 59 | #define pr_fmt(fmt) "[TTM] " fmt |
|
- | 60 | ||
52 | #define pr_fmt(fmt) "[TTM] " fmt |
61 | #include |
53 | 62 | ||
54 | #include |
63 | #include |
55 | #include |
64 | #include |
56 | #include |
65 | #include |
Line 67... | Line 76... | ||
67 | #define pr_err(fmt, ...) \ |
76 | #define pr_err(fmt, ...) \ |
68 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
77 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
Line 69... | Line 78... | ||
69 | 78 | ||
70 | struct ttm_object_file { |
79 | struct ttm_object_file { |
71 | struct ttm_object_device *tdev; |
80 | struct ttm_object_device *tdev; |
72 | rwlock_t lock; |
81 | spinlock_t lock; |
73 | struct list_head ref_list; |
82 | struct list_head ref_list; |
74 | struct drm_open_hash ref_hash[TTM_REF_NUM]; |
83 | struct drm_open_hash ref_hash[TTM_REF_NUM]; |
75 | struct kref refcount; |
84 | struct kref refcount; |
Line 122... | Line 131... | ||
122 | enum ttm_ref_type ref_type; |
131 | enum ttm_ref_type ref_type; |
123 | struct ttm_base_object *obj; |
132 | struct ttm_base_object *obj; |
124 | struct ttm_object_file *tfile; |
133 | struct ttm_object_file *tfile; |
125 | }; |
134 | }; |
Line -... | Line 135... | ||
- | 135 | ||
- | 136 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); |
|
126 | 137 | ||
127 | static inline struct ttm_object_file * |
138 | static inline struct ttm_object_file * |
128 | ttm_object_file_ref(struct ttm_object_file *tfile) |
139 | ttm_object_file_ref(struct ttm_object_file *tfile) |
129 | { |
140 | { |
130 | kref_get(&tfile->refcount); |
141 | kref_get(&tfile->refcount); |
Line 204... | Line 215... | ||
204 | * Note: We don't use synchronize_rcu() here because it's far |
215 | * Note: We don't use synchronize_rcu() here because it's far |
205 | * too slow. It's up to the user to free the object using |
216 | * too slow. It's up to the user to free the object using |
206 | * call_rcu() or ttm_base_object_kfree(). |
217 | * call_rcu() or ttm_base_object_kfree(). |
207 | */ |
218 | */ |
Line 208... | Line -... | ||
208 | - | ||
209 | if (base->refcount_release) { |
219 | |
- | 220 | ttm_object_file_unref(&base->tfile); |
|
210 | ttm_object_file_unref(&base->tfile); |
221 | if (base->refcount_release) |
211 | base->refcount_release(&base); |
222 | base->refcount_release(&base); |
212 | } |
- | |
Line 213... | Line 223... | ||
213 | } |
223 | } |
214 | 224 | ||
215 | void ttm_base_object_unref(struct ttm_base_object **p_base) |
225 | void ttm_base_object_unref(struct ttm_base_object **p_base) |
Line 223... | Line 233... | ||
223 | EXPORT_SYMBOL(ttm_base_object_unref); |
233 | EXPORT_SYMBOL(ttm_base_object_unref); |
Line 224... | Line 234... | ||
224 | 234 | ||
225 | struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, |
235 | struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, |
226 | uint32_t key) |
236 | uint32_t key) |
227 | { |
- | |
228 | struct ttm_object_device *tdev = tfile->tdev; |
237 | { |
229 | struct ttm_base_object *base; |
238 | struct ttm_base_object *base = NULL; |
- | 239 | struct drm_hash_item *hash; |
|
230 | struct drm_hash_item *hash; |
240 | struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
Line 231... | Line 241... | ||
231 | int ret; |
241 | int ret; |
232 | 242 | ||
Line 233... | Line 243... | ||
233 | // rcu_read_lock(); |
243 | // rcu_read_lock(); |
234 | ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash); |
244 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
235 | 245 | ||
- | 246 | if (likely(ret == 0)) { |
|
236 | if (likely(ret == 0)) { |
247 | base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
237 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
248 | if (!kref_get_unless_zero(&base->refcount)) |
Line 238... | Line -... | ||
238 | ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL; |
- | |
239 | } |
249 | base = NULL; |
- | 250 | } |
|
- | 251 | // rcu_read_unlock(); |
|
Line -... | Line 252... | ||
- | 252 | ||
- | 253 | return base; |
|
- | 254 | } |
|
240 | // rcu_read_unlock(); |
255 | EXPORT_SYMBOL(ttm_base_object_lookup); |
- | 256 | ||
- | 257 | struct ttm_base_object * |
|
- | 258 | ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) |
|
- | 259 | { |
|
- | 260 | struct ttm_base_object *base = NULL; |
|
- | 261 | struct drm_hash_item *hash; |
|
- | 262 | struct drm_open_hash *ht = &tdev->object_hash; |
|
241 | 263 | int ret; |
|
242 | if (unlikely(ret != 0)) |
264 | |
243 | return NULL; |
265 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
244 | 266 | ||
Line 245... | Line 267... | ||
245 | if (tfile != base->tfile && !base->shareable) { |
267 | if (likely(ret == 0)) { |
246 | pr_err("Attempted access of non-shareable object\n"); |
268 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
247 | ttm_base_object_unref(&base); |
269 | if (!kref_get_unless_zero(&base->refcount)) |
Line 248... | Line 270... | ||
248 | return NULL; |
270 | base = NULL; |
249 | } |
271 | } |
250 | 272 | ||
251 | return base; |
273 | return base; |
Line 264... | Line 286... | ||
264 | 286 | ||
265 | if (existed != NULL) |
287 | if (existed != NULL) |
Line 266... | Line 288... | ||
266 | *existed = true; |
288 | *existed = true; |
267 | - | ||
268 | while (ret == -EINVAL) { |
289 | |
Line 269... | Line 290... | ||
269 | read_lock(&tfile->lock); |
290 | while (ret == -EINVAL) { |
270 | ret = drm_ht_find_item(ht, base->hash.key, &hash); |
291 | ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
271 | 292 | ||
272 | if (ret == 0) { |
- | |
273 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
293 | if (ret == 0) { |
274 | kref_get(&ref->kref); |
294 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
- | 295 | if (!kref_get_unless_zero(&ref->kref)) { |
|
Line 275... | Line -... | ||
275 | read_unlock(&tfile->lock); |
- | |
276 | break; |
296 | break; |
277 | } |
297 | } |
278 | 298 | } |
|
279 | read_unlock(&tfile->lock); |
299 | |
280 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
300 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
Line 291... | Line 311... | ||
291 | ref->obj = base; |
311 | ref->obj = base; |
292 | ref->tfile = tfile; |
312 | ref->tfile = tfile; |
293 | ref->ref_type = ref_type; |
313 | ref->ref_type = ref_type; |
294 | kref_init(&ref->kref); |
314 | kref_init(&ref->kref); |
Line 295... | Line 315... | ||
295 | 315 | ||
296 | write_lock(&tfile->lock); |
316 | spin_lock(&tfile->lock); |
Line 297... | Line 317... | ||
297 | ret = drm_ht_insert_item(ht, &ref->hash); |
317 | ret = drm_ht_insert_item_rcu(ht, &ref->hash); |
298 | 318 | ||
299 | if (likely(ret == 0)) { |
319 | if (likely(ret == 0)) { |
300 | list_add_tail(&ref->head, &tfile->ref_list); |
320 | list_add_tail(&ref->head, &tfile->ref_list); |
301 | kref_get(&base->refcount); |
321 | kref_get(&base->refcount); |
302 | write_unlock(&tfile->lock); |
322 | spin_unlock(&tfile->lock); |
303 | if (existed != NULL) |
323 | if (existed != NULL) |
304 | *existed = false; |
324 | *existed = false; |
Line 305... | Line 325... | ||
305 | break; |
325 | break; |
306 | } |
326 | } |
Line 307... | Line 327... | ||
307 | 327 | ||
308 | write_unlock(&tfile->lock); |
328 | spin_unlock(&tfile->lock); |
309 | BUG_ON(ret != -EINVAL); |
329 | BUG_ON(ret != -EINVAL); |
Line 324... | Line 344... | ||
324 | struct ttm_object_file *tfile = ref->tfile; |
344 | struct ttm_object_file *tfile = ref->tfile; |
325 | struct drm_open_hash *ht; |
345 | struct drm_open_hash *ht; |
326 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
346 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
Line 327... | Line 347... | ||
327 | 347 | ||
328 | ht = &tfile->ref_hash[ref->ref_type]; |
348 | ht = &tfile->ref_hash[ref->ref_type]; |
329 | (void)drm_ht_remove_item(ht, &ref->hash); |
349 | (void)drm_ht_remove_item_rcu(ht, &ref->hash); |
330 | list_del(&ref->head); |
350 | list_del(&ref->head); |
Line 331... | Line 351... | ||
331 | write_unlock(&tfile->lock); |
351 | spin_unlock(&tfile->lock); |
332 | 352 | ||
Line 333... | Line 353... | ||
333 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
353 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
334 | base->ref_obj_release(base, ref->ref_type); |
354 | base->ref_obj_release(base, ref->ref_type); |
335 | 355 | ||
336 | ttm_base_object_unref(&ref->obj); |
356 | ttm_base_object_unref(&ref->obj); |
337 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
357 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
Line 338... | Line 358... | ||
338 | kfree(ref); |
358 | kfree(ref); |
339 | write_lock(&tfile->lock); |
359 | spin_lock(&tfile->lock); |
340 | } |
360 | } |
341 | 361 | ||
342 | int ttm_ref_object_base_unref(struct ttm_object_file *tfile, |
362 | int ttm_ref_object_base_unref(struct ttm_object_file *tfile, |
343 | unsigned long key, enum ttm_ref_type ref_type) |
363 | unsigned long key, enum ttm_ref_type ref_type) |
344 | { |
364 | { |
Line 345... | Line 365... | ||
345 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
365 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
346 | struct ttm_ref_object *ref; |
366 | struct ttm_ref_object *ref; |
347 | struct drm_hash_item *hash; |
367 | struct drm_hash_item *hash; |
348 | int ret; |
368 | int ret; |
349 | 369 | ||
350 | write_lock(&tfile->lock); |
370 | spin_lock(&tfile->lock); |
351 | ret = drm_ht_find_item(ht, key, &hash); |
371 | ret = drm_ht_find_item(ht, key, &hash); |
352 | if (unlikely(ret != 0)) { |
372 | if (unlikely(ret != 0)) { |
353 | write_unlock(&tfile->lock); |
373 | spin_unlock(&tfile->lock); |
354 | return -EINVAL; |
374 | return -EINVAL; |
355 | } |
375 | } |
356 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
376 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
Line 357... | Line 377... | ||
357 | kref_put(&ref->kref, ttm_ref_object_release); |
377 | kref_put(&ref->kref, ttm_ref_object_release); |
Line 366... | Line 386... | ||
366 | struct list_head *list; |
386 | struct list_head *list; |
367 | unsigned int i; |
387 | unsigned int i; |
368 | struct ttm_object_file *tfile = *p_tfile; |
388 | struct ttm_object_file *tfile = *p_tfile; |
Line 369... | Line 389... | ||
369 | 389 | ||
370 | *p_tfile = NULL; |
390 | *p_tfile = NULL; |
Line 371... | Line 391... | ||
371 | write_lock(&tfile->lock); |
391 | spin_lock(&tfile->lock); |
372 | 392 | ||
373 | /* |
393 | /* |
374 | * Since we release the lock within the loop, we have to |
394 | * Since we release the lock within the loop, we have to |
Line 382... | Line 402... | ||
382 | } |
402 | } |
Line 383... | Line 403... | ||
383 | 403 | ||
384 | for (i = 0; i < TTM_REF_NUM; ++i) |
404 | for (i = 0; i < TTM_REF_NUM; ++i) |
Line 385... | Line 405... | ||
385 | drm_ht_remove(&tfile->ref_hash[i]); |
405 | drm_ht_remove(&tfile->ref_hash[i]); |
386 | 406 | ||
387 | write_unlock(&tfile->lock); |
407 | spin_unlock(&tfile->lock); |
388 | ttm_object_file_unref(&tfile); |
408 | ttm_object_file_unref(&tfile); |
Line 389... | Line 409... | ||
389 | } |
409 | } |
Line 398... | Line 418... | ||
398 | int ret; |
418 | int ret; |
Line 399... | Line 419... | ||
399 | 419 | ||
400 | if (unlikely(tfile == NULL)) |
420 | if (unlikely(tfile == NULL)) |
Line 401... | Line 421... | ||
401 | return NULL; |
421 | return NULL; |
402 | 422 | ||
403 | rwlock_init(&tfile->lock); |
423 | spin_lock_init(&tfile->lock); |
404 | tfile->tdev = tdev; |
424 | tfile->tdev = tdev; |
Line 405... | Line 425... | ||
405 | kref_init(&tfile->refcount); |
425 | kref_init(&tfile->refcount); |
Line 422... | Line 442... | ||
422 | 442 | ||
423 | return NULL; |
443 | return NULL; |
424 | } |
444 | } |
Line 425... | Line 445... | ||
425 | EXPORT_SYMBOL(ttm_object_file_init); |
445 | EXPORT_SYMBOL(ttm_object_file_init); |
426 | 446 | ||
427 | struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global |
447 | struct ttm_object_device * |
- | 448 | ttm_object_device_init(struct ttm_mem_global *mem_glob, |
|
428 | *mem_glob, |
449 | unsigned int hash_order, |
429 | unsigned int hash_order) |
450 | const struct dma_buf_ops *ops) |
430 | { |
451 | { |
Line 431... | Line 452... | ||
431 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
452 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
Line 436... | Line 457... | ||
436 | 457 | ||
437 | tdev->mem_glob = mem_glob; |
458 | tdev->mem_glob = mem_glob; |
438 | spin_lock_init(&tdev->object_lock); |
459 | spin_lock_init(&tdev->object_lock); |
439 | atomic_set(&tdev->object_count, 0); |
460 | atomic_set(&tdev->object_count, 0); |
- | 461 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
|
- | 462 | if (ret != 0) |
|
Line 440... | Line 463... | ||
440 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
463 | goto out_no_object_hash; |
- | 464 | ||
- | 465 | // tdev->ops = *ops; |
|
- | 466 | // tdev->dmabuf_release = tdev->ops.release; |
|
- | 467 | // tdev->ops.release = ttm_prime_dmabuf_release; |
|
441 | 468 | // tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
|
Line -... | Line 469... | ||
- | 469 | // ttm_round_pot(sizeof(struct file)); |
|
442 | if (likely(ret == 0)) |
470 | return tdev; |
443 | return tdev; |
471 | |
444 | 472 | out_no_object_hash: |
|
445 | kfree(tdev); |
473 | kfree(tdev); |