<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 10, 2017 at 4:00 AM, Chris Wilson <span dir="ltr"><<a href="mailto:chris@chris-wilson.co.uk" target="_blank">chris@chris-wilson.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Quoting Jason Ekstrand (2017-08-10 00:53:00)<br>
<span class="gmail-">> On Wed, Aug 9, 2017 at 3:41 PM, Chris Wilson <<a href="mailto:chris@chris-wilson.co.uk">chris@chris-wilson.co.uk</a>> wrote:<br>
</span><span class="gmail-">> However, this installs the proxy into syncobj->fence with the result<br>
> that any concurrent wait also become a WAIT_FOR_SUBMIT. The behaviour<br>
> of drm_syncobj is then quite inconsistent, sometimes it will wait for a<br>
> future fence, sometimes it will report an error.<br>
><br>
><br>
> Yeah, that's not good. I thought about a variety of solutions to try and<br>
> re-use more core dma_fence code. Ultimately I chose the current one because it<br>
> takes a snapshot of the syncobjs and then, from that point forward, it's<br>
> consistent with its snapshot. Nothing I was able to come up with based on core<br>
> dma_fence wait routines does that.<br>
<br>
</span>So if we choose to keep the proxy local to the fence-array and not replace<br>
syncobj->fence, we can still reduce this to a plain dma-fence-array +<br>
wait.<br>
<br>
Pertinent details:<br>
<br>
+static void syncobj_notify(struct drm_syncobj *syncobj, struct dma_fence *fence)<br>
+{<br>
+ struct drm_syncobj_cb *cb, *cn;<br>
+ unsigned long flags;<br>
+<br>
+ /* This is just an opencoded waitqueue; FIXME! */<br>
+ spin_lock_irqsave(&syncobj-><wbr>lock, flags);<br>
+ list_for_each_entry_safe(cb, cn, &syncobj->cb_list, link)<br>
+ cb->func(cb, fence);<br>
+ INIT_LIST_HEAD(&syncobj->cb_<wbr>list);<br>
+ spin_unlock_irqrestore(&<wbr>syncobj->lock, flags);<br>
+}<br>
+<br>
/**<br>
* drm_syncobj_replace_fence - replace fence in a sync object.<br>
* @syncobj: Sync object to replace fence in<br>
@@ -89,7 +109,10 @@ void drm_syncobj_replace_fence(<wbr>struct drm_syncobj *syncobj,<br>
<br>
if (fence)<br>
dma_fence_get(fence);<br>
+<br>
<span class="gmail-"> old_fence = xchg(&syncobj->fence, fence);<br>
</span>+ if (!old_fence && fence)<br>
+ syncobj_notify(syncobj, fence);<br>
<br>
dma_fence_put(old_fence);<br>
}<br>
@@ -124,6 +147,9 @@ void drm_syncobj_free(struct kref *kref)<br>
struct drm_syncobj *syncobj = container_of(kref,<br>
struct drm_syncobj,<br>
refcount);<br>
+<br>
+ syncobj_notify(syncobj, NULL);<br>
+<br>
dma_fence_put(syncobj->fence);<br>
kfree(syncobj);<br>
}<br>
@@ -140,6 +166,8 @@ static int drm_syncobj_create(struct drm_file *file_private,<br>
return -ENOMEM;<br>
<br>
kref_init(&syncobj->refcount);<br>
+ spin_lock_init(&syncobj->lock)<wbr>;<br>
+ INIT_LIST_HEAD(&syncobj->cb_<wbr>list);<br>
<br>
idr_preload(GFP_KERNEL);<br>
spin_lock(&file_private-><wbr>syncobj_table_lock);<br>
<br>
struct future_fence {<br>
+ struct drm_syncobj_cb base;<br>
+ struct dma_fence **slot;<br>
+};<br>
+<br>
+static void future_fence_cb(struct drm_syncobj_cb *cb, struct dma_fence *fence)<br>
+{<br>
+ struct future_fence *ff = container_of(cb, typeof(*ff), base);<br>
+<br>
+ if (fence)<br>
+ dma_fence_replace_proxy(ff-><wbr>slot, fence);<br></blockquote><div><br>Where does this come from? I can't find it on dri-devel and "proxy"
doesn't show up anywhere in the dam-buf sources. What does it do?<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+ else<br>
+ dma_fence_signal(*ff->slot);<br>
+<br>
+ kfree(ff);<br>
+}<br>
+<br>
<span class="gmail-">+int<br>
+drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,<br>
+ struct drm_file *file_private)<br>
+{<br>
+ struct drm_syncobj_wait *args = data;<br>
</span>+ struct dma_fence_array *array;<br>
+ struct dma_fence **fences;<br>
+ unsigned int count, i;<br>
+ long timeout;<br>
+ u32 *handles;<br>
+ int ret;<br>
<span class="gmail-">+<br>
+ BUILD_BUG_ON(sizeof(*fences) < sizeof(*handles));<br>
+<br>
+ if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+ return -ENODEV;<br>
+<br>
</span>+ if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_<wbr>ALL |<br>
+ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_<wbr>FOR_SUBMIT))<br>
<div><div class="gmail-h5">+ return -EINVAL;<br>
+<br>
+ count = args->count_handles;<br>
+ if (!count)<br>
+ return -EINVAL;<br>
+<br>
+ /* Get the handles from userspace */<br>
+ fences = kmalloc_array(count,<br>
+ sizeof(struct dma_fence *),<br>
+ __GFP_NOWARN | GFP_KERNEL);<br>
+ if (!fences)<br>
+ return -ENOMEM;<br>
+<br>
+ handles = (void *)fences + count * (sizeof(*fences) - sizeof(*handles));<br>
+ if (copy_from_user(handles,<br>
+ u64_to_user_ptr(args->handles)<wbr>,<br>
+ sizeof(u32) * count)) {<br>
+ ret = -EFAULT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ for (i = 0; i < count; i++) {<br>
+ struct drm_syncobj *s;<br>
+<br>
+ ret = -ENOENT;<br>
+ s = drm_syncobj_find(file_private, handles[i]);<br>
+ if (s) {<br>
+ ret = 0;<br>
+ spin_lock_irq(&s->lock);<br>
</div></div>+ if (s->fence) {<br>
<span class="gmail-">+ fences[i] = dma_fence_get(s->fence);<br>
</span>+ } else if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_<wbr>FOR_SUBMIT) {<br>
+ struct future_fence *cb;<br>
+<br>
+ cb = kmalloc(sizeof(*cb), GFP_KERNEL);<br>
+ fences[i] = dma_fence_create_proxy();<br>
+ if (cb && fences[i]) {<br>
+ cb->slot = &fences[i];<br>
+ cb->base.func = future_fence_cb;<br>
+ list_add(&cb->base.link, &s->cb_list);<br>
+ } else {<br>
+ kfree(cb);<br>
+ dma_fence_put(fences[i]);<br>
<span class="gmail-">+ ret = -ENOMEM;<br>
+ }<br>
</span><span class="gmail-">+ } else {<br>
+ ret = -EINVAL;<br>
+ }<br>
</span>+ spin_unlock_irq(&s->lock);<br>
<span class="gmail-">+ }<br>
+ if (ret) {<br>
+ count = i;<br>
+ goto err_fences;<br>
+ }<br>
+ }<br>
+<br>
+ array = dma_fence_array_create(count, fences, 0, 0,<br>
+ !(args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_<wbr>ALL));<br>
+ if (!array) {<br>
+ ret = -ENOMEM;<br>
+ goto err_fences;<br>
+ }<br>
+<br>
+ timeout = drm_timeout_abs_to_jiffies(<wbr>args->timeout_nsec);<br>
+ timeout = dma_fence_wait_timeout(&array-<wbr>>base, true, timeout);<br>
+ args->first_signaled = array->first_signaled;<br>
+ dma_fence_put(&array->base);<br>
+<br>
</span>+ return timeout < 0 ? timeout : timeout == 0 ? -ETIME : 0; /* Gah. */<br>
<div class="gmail-HOEnZb"><div class="gmail-h5">+<br>
+err_fences:<br>
+ for (i = 0; i < count; i++)<br>
+ dma_fence_put(fences[i]);<br>
+err:<br>
+ kfree(fences);<br>
+ return ret;<br>
+}<br>
<br>
</div></div></blockquote></div><br></div></div>