diff options
author | Maarten Lankhorst <maarten.lankhorst@canonical.com> | 2014-07-01 06:57:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-08 16:37:35 -0400 |
commit | 04a5faa8cbe5a8eaf152cb88959ba6360c26e702 (patch) | |
tree | fee24a356ead0c38b98d8c3d3b671cd0dd981714 /drivers/dma-buf | |
parent | 9b495a5887994a6d74d5c261d012083a92b94738 (diff) |
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')
-rw-r--r-- | drivers/dma-buf/dma-buf.c | 35 | ||||
-rw-r--r-- | drivers/dma-buf/reservation.c | 156 |
2 files changed, 179 insertions, 12 deletions
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 25e8c4165936..cb8379dfeed5 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c | |||
@@ -134,7 +134,10 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll) | |||
134 | { | 134 | { |
135 | struct dma_buf *dmabuf; | 135 | struct dma_buf *dmabuf; |
136 | struct reservation_object *resv; | 136 | struct reservation_object *resv; |
137 | struct reservation_object_list *fobj; | ||
138 | struct fence *fence_excl; | ||
137 | unsigned long events; | 139 | unsigned long events; |
140 | unsigned shared_count; | ||
138 | 141 | ||
139 | dmabuf = file->private_data; | 142 | dmabuf = file->private_data; |
140 | if (!dmabuf || !dmabuf->resv) | 143 | if (!dmabuf || !dmabuf->resv) |
@@ -150,12 +153,18 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll) | |||
150 | 153 | ||
151 | ww_mutex_lock(&resv->lock, NULL); | 154 | ww_mutex_lock(&resv->lock, NULL); |
152 | 155 | ||
153 | if (resv->fence_excl && (!(events & POLLOUT) || | 156 | fobj = resv->fence; |
154 | resv->fence_shared_count == 0)) { | 157 | if (!fobj) |
158 | goto out; | ||
159 | |||
160 | shared_count = fobj->shared_count; | ||
161 | fence_excl = resv->fence_excl; | ||
162 | |||
163 | if (fence_excl && (!(events & POLLOUT) || shared_count == 0)) { | ||
155 | struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl; | 164 | struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl; |
156 | unsigned long pevents = POLLIN; | 165 | unsigned long pevents = POLLIN; |
157 | 166 | ||
158 | if (resv->fence_shared_count == 0) | 167 | if (shared_count == 0) |
159 | pevents |= POLLOUT; | 168 | pevents |= POLLOUT; |
160 | 169 | ||
161 | spin_lock_irq(&dmabuf->poll.lock); | 170 | spin_lock_irq(&dmabuf->poll.lock); |
@@ -167,19 +176,20 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll) | |||
167 | spin_unlock_irq(&dmabuf->poll.lock); | 176 | spin_unlock_irq(&dmabuf->poll.lock); |
168 | 177 | ||
169 | if (events & pevents) { | 178 | if (events & pevents) { |
170 | if (!fence_add_callback(resv->fence_excl, | 179 | if (!fence_add_callback(fence_excl, &dcb->cb, |
171 | &dcb->cb, dma_buf_poll_cb)) | 180 | dma_buf_poll_cb)) { |
172 | events &= ~pevents; | 181 | events &= ~pevents; |
173 | else | 182 | } else { |
174 | /* | 183 | /* |
175 | * No callback queued, wake up any additional | 184 | * No callback queued, wake up any additional |
176 | * waiters. | 185 | * waiters. |
177 | */ | 186 | */ |
178 | dma_buf_poll_cb(NULL, &dcb->cb); | 187 | dma_buf_poll_cb(NULL, &dcb->cb); |
188 | } | ||
179 | } | 189 | } |
180 | } | 190 | } |
181 | 191 | ||
182 | if ((events & POLLOUT) && resv->fence_shared_count > 0) { | 192 | if ((events & POLLOUT) && shared_count > 0) { |
183 | struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared; | 193 | struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared; |
184 | int i; | 194 | int i; |
185 | 195 | ||
@@ -194,15 +204,18 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll) | |||
194 | if (!(events & POLLOUT)) | 204 | if (!(events & POLLOUT)) |
195 | goto out; | 205 | goto out; |
196 | 206 | ||
197 | for (i = 0; i < resv->fence_shared_count; ++i) | 207 | for (i = 0; i < shared_count; ++i) { |
198 | if (!fence_add_callback(resv->fence_shared[i], | 208 | struct fence *fence = fobj->shared[i]; |
199 | &dcb->cb, dma_buf_poll_cb)) { | 209 | |
210 | if (!fence_add_callback(fence, &dcb->cb, | ||
211 | dma_buf_poll_cb)) { | ||
200 | events &= ~POLLOUT; | 212 | events &= ~POLLOUT; |
201 | break; | 213 | break; |
202 | } | 214 | } |
215 | } | ||
203 | 216 | ||
204 | /* No callback queued, wake up any additional waiters. */ | 217 | /* No callback queued, wake up any additional waiters. */ |
205 | if (i == resv->fence_shared_count) | 218 | if (i == shared_count) |
206 | dma_buf_poll_cb(NULL, &dcb->cb); | 219 | dma_buf_poll_cb(NULL, &dcb->cb); |
207 | } | 220 | } |
208 | 221 | ||
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 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2012-2013 Canonical Ltd | 2 | * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst) |
3 | * | 3 | * |
4 | * Based on bo.c which bears the following copyright notice, | 4 | * Based on bo.c which bears the following copyright notice, |
5 | * but is dual licensed: | 5 | * but is dual licensed: |
@@ -37,3 +37,157 @@ | |||
37 | 37 | ||
38 | DEFINE_WW_CLASS(reservation_ww_class); | 38 | DEFINE_WW_CLASS(reservation_ww_class); |
39 | EXPORT_SYMBOL(reservation_ww_class); | 39 | EXPORT_SYMBOL(reservation_ww_class); |
40 | |||
41 | /* | ||
42 | * Reserve space to add a shared fence to a reservation_object, | ||
43 | * must be called with obj->lock held. | ||
44 | */ | ||
45 | int reservation_object_reserve_shared(struct reservation_object *obj) | ||
46 | { | ||
47 | struct reservation_object_list *fobj, *old; | ||
48 | u32 max; | ||
49 | |||
50 | old = reservation_object_get_list(obj); | ||
51 | |||
52 | if (old && old->shared_max) { | ||
53 | if (old->shared_count < old->shared_max) { | ||
54 | /* perform an in-place update */ | ||
55 | kfree(obj->staged); | ||
56 | obj->staged = NULL; | ||
57 | return 0; | ||
58 | } else | ||
59 | max = old->shared_max * 2; | ||
60 | } else | ||
61 | max = 4; | ||
62 | |||
63 | /* | ||
64 | * resize obj->staged or allocate if it doesn't exist, | ||
65 | * noop if already correct size | ||
66 | */ | ||
67 | fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]), | ||
68 | GFP_KERNEL); | ||
69 | if (!fobj) | ||
70 | return -ENOMEM; | ||
71 | |||
72 | obj->staged = fobj; | ||
73 | fobj->shared_max = max; | ||
74 | return 0; | ||
75 | } | ||
76 | EXPORT_SYMBOL(reservation_object_reserve_shared); | ||
77 | |||
78 | static void | ||
79 | reservation_object_add_shared_inplace(struct reservation_object *obj, | ||
80 | struct reservation_object_list *fobj, | ||
81 | struct fence *fence) | ||
82 | { | ||
83 | u32 i; | ||
84 | |||
85 | for (i = 0; i < fobj->shared_count; ++i) { | ||
86 | if (fobj->shared[i]->context == fence->context) { | ||
87 | struct fence *old_fence = fobj->shared[i]; | ||
88 | |||
89 | fence_get(fence); | ||
90 | |||
91 | fobj->shared[i] = fence; | ||
92 | |||
93 | fence_put(old_fence); | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | fence_get(fence); | ||
99 | fobj->shared[fobj->shared_count] = fence; | ||
100 | /* | ||
101 | * make the new fence visible before incrementing | ||
102 | * fobj->shared_count | ||
103 | */ | ||
104 | smp_wmb(); | ||
105 | fobj->shared_count++; | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | reservation_object_add_shared_replace(struct reservation_object *obj, | ||
110 | struct reservation_object_list *old, | ||
111 | struct reservation_object_list *fobj, | ||
112 | struct fence *fence) | ||
113 | { | ||
114 | unsigned i; | ||
115 | |||
116 | fence_get(fence); | ||
117 | |||
118 | if (!old) { | ||
119 | fobj->shared[0] = fence; | ||
120 | fobj->shared_count = 1; | ||
121 | goto done; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * no need to bump fence refcounts, rcu_read access | ||
126 | * requires the use of kref_get_unless_zero, and the | ||
127 | * references from the old struct are carried over to | ||
128 | * the new. | ||
129 | */ | ||
130 | fobj->shared_count = old->shared_count; | ||
131 | |||
132 | for (i = 0; i < old->shared_count; ++i) { | ||
133 | if (fence && old->shared[i]->context == fence->context) { | ||
134 | fence_put(old->shared[i]); | ||
135 | fobj->shared[i] = fence; | ||
136 | fence = NULL; | ||
137 | } else | ||
138 | fobj->shared[i] = old->shared[i]; | ||
139 | } | ||
140 | if (fence) | ||
141 | fobj->shared[fobj->shared_count++] = fence; | ||
142 | |||
143 | done: | ||
144 | obj->fence = fobj; | ||
145 | kfree(old); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Add a fence to a shared slot, obj->lock must be held, and | ||
150 | * reservation_object_reserve_shared_fence has been called. | ||
151 | */ | ||
152 | void reservation_object_add_shared_fence(struct reservation_object *obj, | ||
153 | struct fence *fence) | ||
154 | { | ||
155 | struct reservation_object_list *old, *fobj = obj->staged; | ||
156 | |||
157 | old = reservation_object_get_list(obj); | ||
158 | obj->staged = NULL; | ||
159 | |||
160 | if (!fobj) { | ||
161 | BUG_ON(old->shared_count == old->shared_max); | ||
162 | reservation_object_add_shared_inplace(obj, old, fence); | ||
163 | } else | ||
164 | reservation_object_add_shared_replace(obj, old, fobj, fence); | ||
165 | } | ||
166 | EXPORT_SYMBOL(reservation_object_add_shared_fence); | ||
167 | |||
168 | void reservation_object_add_excl_fence(struct reservation_object *obj, | ||
169 | struct fence *fence) | ||
170 | { | ||
171 | struct fence *old_fence = obj->fence_excl; | ||
172 | struct reservation_object_list *old; | ||
173 | u32 i = 0; | ||
174 | |||
175 | old = reservation_object_get_list(obj); | ||
176 | if (old) { | ||
177 | i = old->shared_count; | ||
178 | old->shared_count = 0; | ||
179 | } | ||
180 | |||
181 | if (fence) | ||
182 | fence_get(fence); | ||
183 | |||
184 | obj->fence_excl = fence; | ||
185 | |||
186 | /* inplace update, no shared fences */ | ||
187 | while (i--) | ||
188 | fence_put(old->shared[i]); | ||
189 | |||
190 | if (old_fence) | ||
191 | fence_put(old_fence); | ||
192 | } | ||
193 | EXPORT_SYMBOL(reservation_object_add_excl_fence); | ||