1,6 → 1,6 |
/************************************************************************** |
* |
* Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA |
* Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA |
* All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
26,6 → 26,12 |
**************************************************************************/ |
/* |
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
* |
* While no substantial code is shared, the prime code is inspired by |
* drm_prime.c, with |
* Authors: |
* Dave Airlie <airlied@redhat.com> |
* Rob Clark <rob.clark@linaro.org> |
*/ |
/** @file ttm_ref_object.c |
* |
34,6 → 40,7 |
* and release on file close. |
*/ |
|
|
/** |
* struct ttm_object_file |
* |
51,6 → 58,8 |
|
#define pr_fmt(fmt) "[TTM] " fmt |
|
#include <linux/mutex.h> |
|
#include <drm/ttm/ttm_object.h> |
#include <drm/ttm/ttm_module.h> |
#include <linux/list.h> |
69,7 → 78,7 |
|
struct ttm_object_file { |
struct ttm_object_device *tdev; |
rwlock_t lock; |
spinlock_t lock; |
struct list_head ref_list; |
struct drm_open_hash ref_hash[TTM_REF_NUM]; |
struct kref refcount; |
124,6 → 133,8 |
struct ttm_object_file *tfile; |
}; |
|
static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); |
|
static inline struct ttm_object_file * |
ttm_object_file_ref(struct ttm_object_file *tfile) |
{ |
206,11 → 217,10 |
* call_rcu() or ttm_base_object_kfree(). |
*/ |
|
if (base->refcount_release) { |
ttm_object_file_unref(&base->tfile); |
if (base->refcount_release) |
base->refcount_release(&base); |
} |
} |
|
void ttm_base_object_unref(struct ttm_base_object **p_base) |
{ |
225,32 → 235,44 |
struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, |
uint32_t key) |
{ |
struct ttm_object_device *tdev = tfile->tdev; |
struct ttm_base_object *base; |
struct ttm_base_object *base = NULL; |
struct drm_hash_item *hash; |
struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
int ret; |
|
// rcu_read_lock(); |
ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash); |
ret = drm_ht_find_item_rcu(ht, key, &hash); |
|
if (likely(ret == 0)) { |
base = drm_hash_entry(hash, struct ttm_base_object, hash); |
ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL; |
base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
if (!kref_get_unless_zero(&base->refcount)) |
base = NULL; |
} |
// rcu_read_unlock(); |
|
if (unlikely(ret != 0)) |
return NULL; |
return base; |
} |
EXPORT_SYMBOL(ttm_base_object_lookup); |
|
if (tfile != base->tfile && !base->shareable) { |
pr_err("Attempted access of non-shareable object\n"); |
ttm_base_object_unref(&base); |
return NULL; |
struct ttm_base_object * |
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) |
{ |
struct ttm_base_object *base = NULL; |
struct drm_hash_item *hash; |
struct drm_open_hash *ht = &tdev->object_hash; |
int ret; |
|
ret = drm_ht_find_item_rcu(ht, key, &hash); |
|
if (likely(ret == 0)) { |
base = drm_hash_entry(hash, struct ttm_base_object, hash); |
if (!kref_get_unless_zero(&base->refcount)) |
base = NULL; |
} |
|
return base; |
} |
EXPORT_SYMBOL(ttm_base_object_lookup); |
EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); |
|
int ttm_ref_object_add(struct ttm_object_file *tfile, |
struct ttm_base_object *base, |
266,17 → 288,15 |
*existed = true; |
|
while (ret == -EINVAL) { |
read_lock(&tfile->lock); |
ret = drm_ht_find_item(ht, base->hash.key, &hash); |
ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
|
if (ret == 0) { |
ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
kref_get(&ref->kref); |
read_unlock(&tfile->lock); |
if (!kref_get_unless_zero(&ref->kref)) { |
break; |
} |
} |
|
read_unlock(&tfile->lock); |
ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
false, false); |
if (unlikely(ret != 0)) |
293,19 → 313,19 |
ref->ref_type = ref_type; |
kref_init(&ref->kref); |
|
write_lock(&tfile->lock); |
ret = drm_ht_insert_item(ht, &ref->hash); |
spin_lock(&tfile->lock); |
ret = drm_ht_insert_item_rcu(ht, &ref->hash); |
|
if (likely(ret == 0)) { |
list_add_tail(&ref->head, &tfile->ref_list); |
kref_get(&base->refcount); |
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
if (existed != NULL) |
*existed = false; |
break; |
} |
|
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
BUG_ON(ret != -EINVAL); |
|
ttm_mem_global_free(mem_glob, sizeof(*ref)); |
326,9 → 346,9 |
struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
|
ht = &tfile->ref_hash[ref->ref_type]; |
(void)drm_ht_remove_item(ht, &ref->hash); |
(void)drm_ht_remove_item_rcu(ht, &ref->hash); |
list_del(&ref->head); |
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
|
if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
base->ref_obj_release(base, ref->ref_type); |
336,7 → 356,7 |
ttm_base_object_unref(&ref->obj); |
ttm_mem_global_free(mem_glob, sizeof(*ref)); |
kfree(ref); |
write_lock(&tfile->lock); |
spin_lock(&tfile->lock); |
} |
|
int ttm_ref_object_base_unref(struct ttm_object_file *tfile, |
347,15 → 367,15 |
struct drm_hash_item *hash; |
int ret; |
|
write_lock(&tfile->lock); |
spin_lock(&tfile->lock); |
ret = drm_ht_find_item(ht, key, &hash); |
if (unlikely(ret != 0)) { |
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
return -EINVAL; |
} |
ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
kref_put(&ref->kref, ttm_ref_object_release); |
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
return 0; |
} |
EXPORT_SYMBOL(ttm_ref_object_base_unref); |
368,7 → 388,7 |
struct ttm_object_file *tfile = *p_tfile; |
|
*p_tfile = NULL; |
write_lock(&tfile->lock); |
spin_lock(&tfile->lock); |
|
/* |
* Since we release the lock within the loop, we have to |
384,7 → 404,7 |
for (i = 0; i < TTM_REF_NUM; ++i) |
drm_ht_remove(&tfile->ref_hash[i]); |
|
write_unlock(&tfile->lock); |
spin_unlock(&tfile->lock); |
ttm_object_file_unref(&tfile); |
} |
EXPORT_SYMBOL(ttm_object_file_release); |
400,7 → 420,7 |
if (unlikely(tfile == NULL)) |
return NULL; |
|
rwlock_init(&tfile->lock); |
spin_lock_init(&tfile->lock); |
tfile->tdev = tdev; |
kref_init(&tfile->refcount); |
INIT_LIST_HEAD(&tfile->ref_list); |
424,9 → 444,10 |
} |
EXPORT_SYMBOL(ttm_object_file_init); |
|
struct ttm_object_device *ttm_object_device_init(struct ttm_mem_global |
*mem_glob, |
unsigned int hash_order) |
struct ttm_object_device * |
ttm_object_device_init(struct ttm_mem_global *mem_glob, |
unsigned int hash_order, |
const struct dma_buf_ops *ops) |
{ |
struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
int ret; |
438,10 → 459,17 |
spin_lock_init(&tdev->object_lock); |
atomic_set(&tdev->object_count, 0); |
ret = drm_ht_create(&tdev->object_hash, hash_order); |
if (ret != 0) |
goto out_no_object_hash; |
|
if (likely(ret == 0)) |
// tdev->ops = *ops; |
// tdev->dmabuf_release = tdev->ops.release; |
// tdev->ops.release = ttm_prime_dmabuf_release; |
// tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
// ttm_round_pot(sizeof(struct file)); |
return tdev; |
|
out_no_object_hash: |
kfree(tdev); |
return NULL; |
} |