1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Tx., USA
5 * Copyright 2009 VMware, Inc., Palo Alto, CA., USA
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
23 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26 * USE OR OTHER DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
30 * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
37 #include "wsbm_fencemgr.h"
38 #include "wsbm_pool.h"
39 #include "wsbm_manager.h"
41 #include <ttm/ttm_fence_user.h>
45 struct _WsbmFenceClass
47 struct _WsbmListHead head;
48 struct _WsbmMutex mutex;
49 struct _WsbmMutex cmd_mutex;
53 * Note: The struct _WsbmFenceMgr::Mutex should never be held
54 * during sleeps, since that may block fast concurrent access to
61 * Constant members. Need no mutex protection.
63 struct _WsbmFenceMgrCreateInfo info;
67 * Atomic members. No mutex protection.
70 struct _WsbmAtomic count;
73 * These members are protected by this->mutex
76 struct _WsbmFenceClass *classes;
80 struct _WsbmFenceObject
84 * These members are constant and need no mutex protection.
85 * Note that @private may point to a structure with its own
86 * mutex protection, that we don't care about.
89 struct _WsbmFenceMgr *mgr;
95 * Atomic members. No mutex protection. note that
96 * @signaled types is updated using a compare-and-swap
97 * scheme to guarantee atomicity.
100 struct _WsbmAtomic refCount;
101 struct _WsbmAtomic signaled_types;
104 * These members are protected by mgr->mutex.
106 struct _WsbmListHead head;
110 wsbmFenceType(struct _WsbmFenceObject *fence)
112 return fence->fence_type;
115 struct _WsbmFenceMgr *
116 wsbmFenceMgrCreate(const struct _WsbmFenceMgrCreateInfo *info)
118 struct _WsbmFenceMgr *tmp;
122 tmp = calloc(1, sizeof(*tmp));
127 tmp->classes = calloc(tmp->info.num_classes, sizeof(*tmp->classes));
131 for (i = 0; i < tmp->info.num_classes; ++i) {
132 struct _WsbmFenceClass *fc = &tmp->classes[i];
134 WSBMINITLISTHEAD(&fc->head);
135 ret = WSBM_MUTEX_INIT(&fc->mutex);
138 ret = WSBM_MUTEX_INIT(&fc->cmd_mutex);
140 WSBM_MUTEX_FREE(&fc->mutex);
144 wsbmAtomicSet(&tmp->count, 0);
149 for (j = 0; j < i; ++j) {
150 WSBM_MUTEX_FREE(&tmp->classes[j].mutex);
151 WSBM_MUTEX_FREE(&tmp->classes[j].cmd_mutex);
161 wsbmFenceUnreference(struct _WsbmFenceObject **pFence)
163 struct _WsbmFenceObject *fence = *pFence;
164 struct _WsbmFenceMgr *mgr;
171 if (wsbmAtomicDecZero(&fence->refCount)) {
172 struct _WsbmFenceClass *fc = &mgr->classes[fence->fence_class];
174 WSBM_MUTEX_LOCK(&fc->mutex);
175 WSBMLISTDELINIT(&fence->head);
176 WSBM_MUTEX_UNLOCK(&fc->mutex);
178 mgr->info.unreference(mgr, &fence->private);
180 wsbmAtomicDecZero(&mgr->count);
186 wsbmSignalPreviousFences(struct _WsbmFenceMgr *mgr,
187 struct _WsbmListHead *list,
188 uint32_t fence_class, uint32_t signaled_types)
190 struct _WsbmFenceClass *fc = &mgr->classes[fence_class];
191 struct _WsbmFenceObject *entry;
192 struct _WsbmListHead *prev;
193 uint32_t old_signaled_types;
196 WSBM_MUTEX_LOCK(&fc->mutex);
197 while (list != &fc->head && list->next != list) {
198 entry = WSBMLISTENTRY(list, struct _WsbmFenceObject, head);
203 old_signaled_types = wsbmAtomicRead(&entry->signaled_types);
205 old_signaled_types | (signaled_types & entry->fence_type);
206 if (signaled_types == old_signaled_types)
210 wsbmAtomicCmpXchg(&entry->signaled_types, old_signaled_types,
212 } while (ret_st != old_signaled_types);
214 if (signaled_types == entry->fence_type)
215 WSBMLISTDELINIT(list);
219 WSBM_MUTEX_UNLOCK(&fc->mutex);
223 wsbmFenceFinish(struct _WsbmFenceObject *fence, uint32_t fence_type,
226 struct _WsbmFenceMgr *mgr = fence->mgr;
229 if ((wsbmAtomicRead(&fence->signaled_types) & fence_type) == fence_type)
232 ret = mgr->info.finish(mgr, fence->private, fence_type, lazy_hint);
236 wsbmSignalPreviousFences(mgr, &fence->head, fence->fence_class,
243 wsbmFenceSignaledTypeCached(struct _WsbmFenceObject * fence)
245 return wsbmAtomicRead(&fence->signaled_types);
249 wsbmFenceSignaledType(struct _WsbmFenceObject *fence, uint32_t flush_type,
253 struct _WsbmFenceMgr *mgr;
254 uint32_t signaled_types;
255 uint32_t old_signaled_types;
259 *signaled = wsbmAtomicRead(&fence->signaled_types);
260 if ((*signaled & flush_type) == flush_type)
263 ret = mgr->info.signaled(mgr, fence->private, flush_type, signaled);
265 *signaled = wsbmAtomicRead(&fence->signaled_types);
270 old_signaled_types = wsbmAtomicRead(&fence->signaled_types);
271 signaled_types = old_signaled_types | *signaled;
272 if (signaled_types == old_signaled_types)
275 ret_st = wsbmAtomicCmpXchg(&fence->signaled_types, old_signaled_types,
277 if (old_signaled_types == ret_st)
278 wsbmSignalPreviousFences(mgr, &fence->head, fence->fence_class,
280 } while (old_signaled_types != ret_st);
287 struct _WsbmFenceObject *
288 wsbmFenceReference(struct _WsbmFenceObject *fence)
292 wsbmAtomicInc(&fence->refCount);
296 struct _WsbmFenceObject *
297 wsbmFenceCreateSig(struct _WsbmFenceMgr *mgr, uint32_t fence_class,
298 uint32_t fence_type, uint32_t signaled_types,
299 void *private, size_t private_size)
301 struct _WsbmFenceClass *fc = &mgr->classes[fence_class];
302 struct _WsbmFenceObject *fence;
303 size_t fence_size = sizeof(*fence);
306 fence_size = ((fence_size + 15) & ~15);
308 fence = calloc(1, fence_size + private_size);
313 wsbmAtomicSet(&fence->refCount, 1);
315 fence->fence_class = fence_class;
316 fence->fence_type = fence_type;
317 wsbmAtomicSet(&fence->signaled_types, signaled_types);
318 fence->private = private;
320 fence->private = (void *)(((uint8_t *) fence) + fence_size);
321 memcpy(fence->private, private, private_size);
324 WSBM_MUTEX_LOCK(&fc->mutex);
325 WSBMLISTADDTAIL(&fence->head, &fc->head);
326 WSBM_MUTEX_UNLOCK(&fc->mutex);
327 wsbmAtomicInc(&mgr->count);
332 int ret = mgr->info.finish(mgr, private, fence_type, 0);
340 mgr->info.unreference(mgr, &private);
344 struct _WsbmFenceObject *
345 wsbmFenceCreate(struct _WsbmFenceMgr *mgr, uint32_t fence_class,
346 uint32_t fence_type, void *private, size_t private_size)
348 return wsbmFenceCreateSig(mgr, fence_class, fence_type, 0, private,
352 struct _WsbmTTMFenceMgrPriv
355 unsigned int devOffset;
359 tSignaled(struct _WsbmFenceMgr *mgr, void *private, uint32_t flush_type,
360 uint32_t * signaled_type)
362 struct _WsbmTTMFenceMgrPriv *priv =
363 (struct _WsbmTTMFenceMgrPriv *)mgr->private;
364 union ttm_fence_signaled_arg arg;
367 arg.req.handle = (unsigned long)private;
368 arg.req.fence_type = flush_type;
372 ret = drmCommandWriteRead(priv->fd, priv->devOffset + TTM_FENCE_SIGNALED,
377 *signaled_type = arg.rep.signaled_types;
382 tFinish(struct _WsbmFenceMgr *mgr, void *private, uint32_t fence_type,
385 struct _WsbmTTMFenceMgrPriv *priv =
386 (struct _WsbmTTMFenceMgrPriv *)mgr->private;
387 union ttm_fence_finish_arg arg =
388 {.req = {.handle = (unsigned long)private,
389 .fence_type = fence_type,
390 .mode = (lazy_hint) ? TTM_FENCE_FINISH_MODE_LAZY : 0}
395 ret = drmCommandWriteRead(priv->fd, priv->devOffset + TTM_FENCE_FINISH,
397 } while (ret == -EAGAIN || ret == -ERESTART);
403 tUnref(struct _WsbmFenceMgr *mgr, void **private)
405 struct _WsbmTTMFenceMgrPriv *priv =
406 (struct _WsbmTTMFenceMgrPriv *)mgr->private;
407 struct ttm_fence_unref_arg arg = {.handle = (unsigned long)*private };
411 return drmCommandWrite(priv->fd, priv->devOffset + TTM_FENCE_UNREF,
415 struct _WsbmFenceMgr *
416 wsbmFenceMgrTTMInit(int fd, unsigned int numClass, unsigned int devOffset)
418 struct _WsbmFenceMgrCreateInfo info;
419 struct _WsbmFenceMgr *mgr;
420 struct _WsbmTTMFenceMgrPriv *priv = malloc(sizeof(*priv));
426 priv->devOffset = devOffset;
428 info.flags = WSBM_FENCE_CLASS_ORDERED;
429 info.num_classes = numClass;
430 info.signaled = tSignaled;
431 info.finish = tFinish;
432 info.unreference = tUnref;
434 mgr = wsbmFenceMgrCreate(&info);
440 mgr->private = (void *)priv;
445 wsbmFenceCmdLock(struct _WsbmFenceMgr *mgr, uint32_t fence_class)
447 WSBM_MUTEX_LOCK(&mgr->classes[fence_class].cmd_mutex);
451 wsbmFenceCmdUnlock(struct _WsbmFenceMgr *mgr, uint32_t fence_class)
453 WSBM_MUTEX_UNLOCK(&mgr->classes[fence_class].cmd_mutex);
457 wsbmFenceMgrTTMTakedown(struct _WsbmFenceMgr *mgr)
467 for (i = 0; i < mgr->info.num_classes; ++i) {
468 WSBM_MUTEX_FREE(&mgr->classes[i].mutex);
469 WSBM_MUTEX_FREE(&mgr->classes[i].cmd_mutex);