diff options
author | Maarten Lankhorst <maarten.lankhorst@canonical.com> | 2014-07-01 12:57:54 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-08 13:37:35 -0700 |
commit | 04a5faa8cbe5a8eaf152cb88959ba6360c26e702 (patch) | |
tree | fee24a356ead0c38b98d8c3d3b671cd0dd981714 /drivers/dma-buf/reservation.c | |
parent | 9b495a5887994a6d74d5c261d012083a92b94738 (diff) | |
download | linux-04a5faa8cbe5a8eaf152cb88959ba6360c26e702.tar.bz2 |
reservation: update api and add some helpers
Move the list of shared fences to a struct, and return it in
reservation_object_get_list().
Add reservation_object_get_excl to get the exclusive fence.
Add reservation_object_reserve_shared(), which reserves space
in the reservation_object for 1 more shared fence.
reservation_object_add_shared_fence() and
reservation_object_add_excl_fence() are used to assign a new
fence to a reservation_object pointer, to complete a reservation.
Changes since v1:
- Add reservation_object_get_excl, reorder code a bit.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Acked-by: Sumit Semwal <sumit.semwal@linaro.org>
Acked-by: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/dma-buf/reservation.c')
-rw-r--r-- | drivers/dma-buf/reservation.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index a73fbf3b8e56..e6166723a9ae 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Canonical Ltd + * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst) * * Based on bo.c which bears the following copyright notice, * but is dual licensed: @@ -37,3 +37,157 @@ DEFINE_WW_CLASS(reservation_ww_class); EXPORT_SYMBOL(reservation_ww_class); + +/* + * Reserve space to add a shared fence to a reservation_object, + * must be called with obj->lock held. + */ +int reservation_object_reserve_shared(struct reservation_object *obj) +{ + struct reservation_object_list *fobj, *old; + u32 max; + + old = reservation_object_get_list(obj); + + if (old && old->shared_max) { + if (old->shared_count < old->shared_max) { + /* perform an in-place update */ + kfree(obj->staged); + obj->staged = NULL; + return 0; + } else + max = old->shared_max * 2; + } else + max = 4; + + /* + * resize obj->staged or allocate if it doesn't exist, + * noop if already correct size + */ + fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]), + GFP_KERNEL); + if (!fobj) + return -ENOMEM; + + obj->staged = fobj; + fobj->shared_max = max; + return 0; +} +EXPORT_SYMBOL(reservation_object_reserve_shared); + +static void +reservation_object_add_shared_inplace(struct reservation_object *obj, + struct reservation_object_list *fobj, + struct fence *fence) +{ + u32 i; + + for (i = 0; i < fobj->shared_count; ++i) { + if (fobj->shared[i]->context == fence->context) { + struct fence *old_fence = fobj->shared[i]; + + fence_get(fence); + + fobj->shared[i] = fence; + + fence_put(old_fence); + return; + } + } + + fence_get(fence); + fobj->shared[fobj->shared_count] = fence; + /* + * make the new fence visible before incrementing + * fobj->shared_count + */ + smp_wmb(); + fobj->shared_count++; +} + +static void +reservation_object_add_shared_replace(struct reservation_object *obj, + struct reservation_object_list *old, + struct reservation_object_list *fobj, + struct fence *fence) +{ + unsigned i; + + fence_get(fence); + + if (!old) { + fobj->shared[0] = fence; + fobj->shared_count = 1; + goto done; + } + + /* + * no need to bump fence refcounts, rcu_read access + * requires the use of kref_get_unless_zero, and the + * references from the old struct are carried over to + * the new. + */ + fobj->shared_count = old->shared_count; + + for (i = 0; i < old->shared_count; ++i) { + if (fence && old->shared[i]->context == fence->context) { + fence_put(old->shared[i]); + fobj->shared[i] = fence; + fence = NULL; + } else + fobj->shared[i] = old->shared[i]; + } + if (fence) + fobj->shared[fobj->shared_count++] = fence; + +done: + obj->fence = fobj; + kfree(old); +} + +/* + * Add a fence to a shared slot, obj->lock must be held, and + * reservation_object_reserve_shared_fence has been called. + */ +void reservation_object_add_shared_fence(struct reservation_object *obj, + struct fence *fence) +{ + struct reservation_object_list *old, *fobj = obj->staged; + + old = reservation_object_get_list(obj); + obj->staged = NULL; + + if (!fobj) { + BUG_ON(old->shared_count == old->shared_max); + reservation_object_add_shared_inplace(obj, old, fence); + } else + reservation_object_add_shared_replace(obj, old, fobj, fence); +} +EXPORT_SYMBOL(reservation_object_add_shared_fence); + +void reservation_object_add_excl_fence(struct reservation_object *obj, + struct fence *fence) +{ + struct fence *old_fence = obj->fence_excl; + struct reservation_object_list *old; + u32 i = 0; + + old = reservation_object_get_list(obj); + if (old) { + i = old->shared_count; + old->shared_count = 0; + } + + if (fence) + fence_get(fence); + + obj->fence_excl = fence; + + /* inplace update, no shared fences */ + while (i--) + fence_put(old->shared[i]); + + if (old_fence) + fence_put(old_fence); +} +EXPORT_SYMBOL(reservation_object_add_excl_fence); |