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