]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 7 Dec 2017 10:54:14 +0000 (11:54 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 7 Dec 2017 10:54:14 +0000 (11:54 +0100)
added patches:
dma-buf-dma-fence-extract-__dma_fence_is_later.patch
dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch
dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch
dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch
dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch
dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch
dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch
dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch
dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch
dma-buf-sw_sync-move-timeline_fence_ops-around.patch
dma-fence-clear-fence-status-during-dma_fence_init.patch
dma-fence-introduce-drm_fence_set_error-helper.patch
dma-fence-wrap-querying-the-fence-status.patch

14 files changed:
queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch [new file with mode: 0644]
queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch [new file with mode: 0644]
queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch [new file with mode: 0644]
queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch [new file with mode: 0644]
queue-4.9/dma-fence-wrap-querying-the-fence-status.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch b/queue-4.9/dma-buf-dma-fence-extract-__dma_fence_is_later.patch
new file mode 100644 (file)
index 0000000..628013f
--- /dev/null
@@ -0,0 +1,58 @@
+From 8111477663813caa1a4469cfe6afaae36cd04513 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 13:59:24 +0100
+Subject: dma-buf/dma-fence: Extract __dma_fence_is_later()
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 8111477663813caa1a4469cfe6afaae36cd04513 upstream.
+
+Often we have the task of comparing two seqno known to be on the same
+context, so provide a common __dma_fence_is_later().
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-1-chris@chris-wilson.co.uk
+[renamed to __fence_is_later() - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/fence.h |   15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/include/linux/fence.h
++++ b/include/linux/fence.h
+@@ -281,6 +281,19 @@ fence_is_signaled(struct fence *fence)
+ }
+ /**
++ * __fence_is_later - return if f1 is chronologically later than f2
++ * @f1:       [in]    the first fence's seqno
++ * @f2:       [in]    the second fence's seqno from the same context
++ *
++ * Returns true if f1 is chronologically later than f2. Both fences must be
++ * from the same context, since a seqno is not common across contexts.
++ */
++static inline bool __fence_is_later(u32 f1, u32 f2)
++{
++      return (int)(f1 - f2) > 0;
++}
++
++/**
+  * fence_is_later - return if f1 is chronologically later than f2
+  * @f1:       [in]    the first fence from the same context
+  * @f2:       [in]    the second fence from the same context
+@@ -293,7 +306,7 @@ static inline bool fence_is_later(struct
+       if (WARN_ON(f1->context != f2->context))
+               return false;
+-      return (int)(f1->seqno - f2->seqno) > 0;
++      return __fence_is_later(f1->seqno, f2->seqno);
+ }
+ /**
diff --git a/queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch b/queue-4.9/dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch
new file mode 100644 (file)
index 0000000..a95d2f1
--- /dev/null
@@ -0,0 +1,204 @@
+From d3862e44daa7a0c94d2f6193502a8c49379acfce Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 22:05:32 +0100
+Subject: dma-buf/sw-sync: Fix locking around sync_timeline lists
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit d3862e44daa7a0c94d2f6193502a8c49379acfce upstream.
+
+The sync_pt were not adding themselves atomically to the timeline lists,
+corruption imminent.  Only a single list is required to track the
+unsignaled sync_pt, so reduce it and rename the lock more appropriately
+along with using idiomatic names to distinguish a list from links along
+it.
+
+v2: Prevent spinlock recursion on free during create (next patch) and
+fixup crossref in kerneldoc
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629210532.5617-1-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c    |   48 +++++++++++++++++--------------------------
+ drivers/dma-buf/sync_debug.c |    9 +++-----
+ drivers/dma-buf/sync_debug.h |   22 +++++++------------
+ 3 files changed, 31 insertions(+), 48 deletions(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -96,9 +96,8 @@ struct sync_timeline *sync_timeline_crea
+       obj->context = fence_context_alloc(1);
+       strlcpy(obj->name, name, sizeof(obj->name));
+-      INIT_LIST_HEAD(&obj->child_list_head);
+-      INIT_LIST_HEAD(&obj->active_list_head);
+-      spin_lock_init(&obj->child_list_lock);
++      INIT_LIST_HEAD(&obj->pt_list);
++      spin_lock_init(&obj->lock);
+       sync_timeline_debug_add(obj);
+@@ -139,17 +138,15 @@ static void sync_timeline_signal(struct
+       trace_sync_timeline(obj);
+-      spin_lock_irq(&obj->child_list_lock);
++      spin_lock_irq(&obj->lock);
+       obj->value += inc;
+-      list_for_each_entry_safe(pt, next, &obj->active_list_head,
+-                               active_list) {
++      list_for_each_entry_safe(pt, next, &obj->pt_list, link)
+               if (fence_is_signaled_locked(&pt->base))
+-                      list_del_init(&pt->active_list);
+-      }
++                      list_del_init(&pt->link);
+-      spin_unlock_irq(&obj->child_list_lock);
++      spin_unlock_irq(&obj->lock);
+ }
+ /**
+@@ -171,15 +168,15 @@ static struct sync_pt *sync_pt_create(st
+       if (!pt)
+               return NULL;
+-      spin_lock_irq(&obj->child_list_lock);
+-
+       sync_timeline_get(obj);
+-      fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock,
++      fence_init(&pt->base, &timeline_fence_ops, &obj->lock,
+                  obj->context, value);
+-      list_add_tail(&pt->child_list, &obj->child_list_head);
+-      INIT_LIST_HEAD(&pt->active_list);
++      INIT_LIST_HEAD(&pt->link);
+-      spin_unlock_irq(&obj->child_list_lock);
++      spin_lock_irq(&obj->lock);
++      if (!fence_is_signaled_locked(&pt->base))
++              list_add_tail(&pt->link, &obj->pt_list);
++      spin_unlock_irq(&obj->lock);
+       return pt;
+ }
+@@ -200,15 +197,15 @@ static void timeline_fence_release(struc
+ {
+       struct sync_pt *pt = fence_to_sync_pt(fence);
+       struct sync_timeline *parent = fence_parent(fence);
+-      unsigned long flags;
+-      spin_lock_irqsave(fence->lock, flags);
++      if (!list_empty(&pt->link)) {
++              unsigned long flags;
+-      list_del(&pt->child_list);
+-      if (!list_empty(&pt->active_list))
+-              list_del(&pt->active_list);
+-
+-      spin_unlock_irqrestore(fence->lock, flags);
++              spin_lock_irqsave(fence->lock, flags);
++              if (!list_empty(&pt->link))
++                      list_del(&pt->link);
++              spin_unlock_irqrestore(fence->lock, flags);
++      }
+       sync_timeline_put(parent);
+       fence_free(fence);
+@@ -223,13 +220,6 @@ static bool timeline_fence_signaled(stru
+ static bool timeline_fence_enable_signaling(struct fence *fence)
+ {
+-      struct sync_pt *pt = fence_to_sync_pt(fence);
+-      struct sync_timeline *parent = fence_parent(fence);
+-
+-      if (timeline_fence_signaled(fence))
+-              return false;
+-
+-      list_add_tail(&pt->active_list, &parent->active_list_head);
+       return true;
+ }
+--- a/drivers/dma-buf/sync_debug.c
++++ b/drivers/dma-buf/sync_debug.c
+@@ -119,13 +119,12 @@ static void sync_print_obj(struct seq_fi
+       seq_printf(s, "%s: %d\n", obj->name, obj->value);
+-      spin_lock_irq(&obj->child_list_lock);
+-      list_for_each(pos, &obj->child_list_head) {
+-              struct sync_pt *pt =
+-                      container_of(pos, struct sync_pt, child_list);
++      spin_lock_irq(&obj->lock);
++      list_for_each(pos, &obj->pt_list) {
++              struct sync_pt *pt = container_of(pos, struct sync_pt, link);
+               sync_print_fence(s, &pt->base, false);
+       }
+-      spin_unlock_irq(&obj->child_list_lock);
++      spin_unlock_irq(&obj->lock);
+ }
+ static void sync_print_sync_file(struct seq_file *s,
+--- a/drivers/dma-buf/sync_debug.h
++++ b/drivers/dma-buf/sync_debug.h
+@@ -24,43 +24,37 @@
+  * struct sync_timeline - sync object
+  * @kref:             reference count on fence.
+  * @name:             name of the sync_timeline. Useful for debugging
+- * @child_list_head:  list of children sync_pts for this sync_timeline
+- * @child_list_lock:  lock protecting @child_list_head and fence.status
+- * @active_list_head: list of active (unsignaled/errored) sync_pts
++ * @lock:             lock protecting @pt_list and @value
++ * @pt_list:          list of active (unsignaled/errored) sync_pts
+  * @sync_timeline_list:       membership in global sync_timeline_list
+  */
+ struct sync_timeline {
+       struct kref             kref;
+       char                    name[32];
+-      /* protected by child_list_lock */
++      /* protected by lock */
+       u64                     context;
+       int                     value;
+-      struct list_head        child_list_head;
+-      spinlock_t              child_list_lock;
+-
+-      struct list_head        active_list_head;
++      struct list_head        pt_list;
++      spinlock_t              lock;
+       struct list_head        sync_timeline_list;
+ };
+ static inline struct sync_timeline *fence_parent(struct fence *fence)
+ {
+-      return container_of(fence->lock, struct sync_timeline,
+-                          child_list_lock);
++      return container_of(fence->lock, struct sync_timeline, lock);
+ }
+ /**
+  * struct sync_pt - sync_pt object
+  * @base: base fence object
+- * @child_list: sync timeline child's list
+- * @active_list: sync timeline active child's list
++ * @link: link on the sync timeline's list
+  */
+ struct sync_pt {
+       struct fence base;
+-      struct list_head child_list;
+-      struct list_head active_list;
++      struct list_head link;
+ };
+ #ifdef CONFIG_SW_SYNC
diff --git a/queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch b/queue-4.9/dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch
new file mode 100644 (file)
index 0000000..820c46f
--- /dev/null
@@ -0,0 +1,38 @@
+From 61894b02716f122dd7662d5d89f5b2245ca551e2 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 13:59:25 +0100
+Subject: dma-buf/sw-sync: Fix the is-signaled test to handle u32 wraparound
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 61894b02716f122dd7662d5d89f5b2245ca551e2 upstream.
+
+Use the canonical __dma_fence_is_later() to compare the fence seqno
+against the timeline seqno to check if the fence is signaled.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-2-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -219,7 +219,7 @@ static bool timeline_fence_signaled(stru
+ {
+       struct sync_timeline *parent = fence_parent(fence);
+-      return (fence->seqno > parent->value) ? false : true;
++      return !__fence_is_later(fence->seqno, parent->value);
+ }
+ static bool timeline_fence_enable_signaling(struct fence *fence)
diff --git a/queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch b/queue-4.9/dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch
new file mode 100644 (file)
index 0000000..0f530d8
--- /dev/null
@@ -0,0 +1,41 @@
+From 8f66d3aa1735bc95ae58d846a157357e8d41abb8 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 13:59:26 +0100
+Subject: dma-buf/sw-sync: Prevent user overflow on timeline advance
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 8f66d3aa1735bc95ae58d846a157357e8d41abb8 upstream.
+
+The timeline is u32, which limits any single advance to INT_MAX so that
+we can detect all fences that need signaling.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-3-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -345,6 +345,11 @@ static long sw_sync_ioctl_inc(struct syn
+       if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
+               return -EFAULT;
++      while (value > INT_MAX)  {
++              sync_timeline_signal(obj, INT_MAX);
++              value -= INT_MAX;
++      }
++
+       sync_timeline_signal(obj, value);
+       return 0;
diff --git a/queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch b/queue-4.9/dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch
new file mode 100644 (file)
index 0000000..247511f
--- /dev/null
@@ -0,0 +1,151 @@
+From a6aa8fca4d792c72947e341d7842d2f700534335 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 13:59:27 +0100
+Subject: dma-buf/sw-sync: Reduce irqsave/irqrestore from known context
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit a6aa8fca4d792c72947e341d7842d2f700534335 upstream.
+
+If we know the context under which we are called, then we can use the
+simpler form of spin_lock_irq (saving the save/restore).
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-4-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c    |   15 +++++++++------
+ drivers/dma-buf/sync_debug.c |   14 ++++++--------
+ 2 files changed, 15 insertions(+), 14 deletions(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -135,12 +135,11 @@ static void sync_timeline_put(struct syn
+  */
+ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
+ {
+-      unsigned long flags;
+       struct sync_pt *pt, *next;
+       trace_sync_timeline(obj);
+-      spin_lock_irqsave(&obj->child_list_lock, flags);
++      spin_lock_irq(&obj->child_list_lock);
+       obj->value += inc;
+@@ -150,7 +149,7 @@ static void sync_timeline_signal(struct
+                       list_del_init(&pt->active_list);
+       }
+-      spin_unlock_irqrestore(&obj->child_list_lock, flags);
++      spin_unlock_irq(&obj->child_list_lock);
+ }
+ /**
+@@ -167,7 +166,6 @@ static void sync_timeline_signal(struct
+ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size,
+                            unsigned int value)
+ {
+-      unsigned long flags;
+       struct sync_pt *pt;
+       if (size < sizeof(*pt))
+@@ -177,13 +175,16 @@ static struct sync_pt *sync_pt_create(st
+       if (!pt)
+               return NULL;
+-      spin_lock_irqsave(&obj->child_list_lock, flags);
++      spin_lock_irq(&obj->child_list_lock);
++
+       sync_timeline_get(obj);
+       fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock,
+                  obj->context, value);
+       list_add_tail(&pt->child_list, &obj->child_list_head);
+       INIT_LIST_HEAD(&pt->active_list);
+-      spin_unlock_irqrestore(&obj->child_list_lock, flags);
++
++      spin_unlock_irq(&obj->child_list_lock);
++
+       return pt;
+ }
+@@ -206,9 +207,11 @@ static void timeline_fence_release(struc
+       unsigned long flags;
+       spin_lock_irqsave(fence->lock, flags);
++
+       list_del(&pt->child_list);
+       if (!list_empty(&pt->active_list))
+               list_del(&pt->active_list);
++
+       spin_unlock_irqrestore(fence->lock, flags);
+       sync_timeline_put(parent);
+--- a/drivers/dma-buf/sync_debug.c
++++ b/drivers/dma-buf/sync_debug.c
+@@ -116,17 +116,16 @@ static void sync_print_fence(struct seq_
+ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
+ {
+       struct list_head *pos;
+-      unsigned long flags;
+       seq_printf(s, "%s: %d\n", obj->name, obj->value);
+-      spin_lock_irqsave(&obj->child_list_lock, flags);
++      spin_lock_irq(&obj->child_list_lock);
+       list_for_each(pos, &obj->child_list_head) {
+               struct sync_pt *pt =
+                       container_of(pos, struct sync_pt, child_list);
+               sync_print_fence(s, &pt->base, false);
+       }
+-      spin_unlock_irqrestore(&obj->child_list_lock, flags);
++      spin_unlock_irq(&obj->child_list_lock);
+ }
+ static void sync_print_sync_file(struct seq_file *s,
+@@ -149,12 +148,11 @@ static void sync_print_sync_file(struct
+ static int sync_debugfs_show(struct seq_file *s, void *unused)
+ {
+-      unsigned long flags;
+       struct list_head *pos;
+       seq_puts(s, "objs:\n--------------\n");
+-      spin_lock_irqsave(&sync_timeline_list_lock, flags);
++      spin_lock_irq(&sync_timeline_list_lock);
+       list_for_each(pos, &sync_timeline_list_head) {
+               struct sync_timeline *obj =
+                       container_of(pos, struct sync_timeline,
+@@ -163,11 +161,11 @@ static int sync_debugfs_show(struct seq_
+               sync_print_obj(s, obj);
+               seq_puts(s, "\n");
+       }
+-      spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
++      spin_unlock_irq(&sync_timeline_list_lock);
+       seq_puts(s, "fences:\n--------------\n");
+-      spin_lock_irqsave(&sync_file_list_lock, flags);
++      spin_lock_irq(&sync_file_list_lock);
+       list_for_each(pos, &sync_file_list_head) {
+               struct sync_file *sync_file =
+                       container_of(pos, struct sync_file, sync_file_list);
+@@ -175,7 +173,7 @@ static int sync_debugfs_show(struct seq_
+               sync_print_sync_file(s, sync_file);
+               seq_puts(s, "\n");
+       }
+-      spin_unlock_irqrestore(&sync_file_list_lock, flags);
++      spin_unlock_irq(&sync_file_list_lock);
+       return 0;
+ }
diff --git a/queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch b/queue-4.9/dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch
new file mode 100644 (file)
index 0000000..9cbc398
--- /dev/null
@@ -0,0 +1,66 @@
+From 3b52ce44e720c240afc4c4b03140d7b7811b23bd Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 13:59:28 +0100
+Subject: dma-buf/sw-sync: sync_pt is private and of fixed size
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 3b52ce44e720c240afc4c4b03140d7b7811b23bd upstream.
+
+Since sync_pt is only allocated from a single location and is no longer
+the base class for fences (that is struct dma_fence) it no longer needs
+a generic unsized allocator.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629125930.821-5-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |   12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -155,7 +155,6 @@ static void sync_timeline_signal(struct
+ /**
+  * sync_pt_create() - creates a sync pt
+  * @parent:   fence's parent sync_timeline
+- * @size:     size to allocate for this pt
+  * @inc:      value of the fence
+  *
+  * Creates a new sync_pt as a child of @parent.  @size bytes will be
+@@ -163,15 +162,12 @@ static void sync_timeline_signal(struct
+  * the generic sync_timeline struct. Returns the sync_pt object or
+  * NULL in case of error.
+  */
+-static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size,
+-                           unsigned int value)
++static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
++                                    unsigned int value)
+ {
+       struct sync_pt *pt;
+-      if (size < sizeof(*pt))
+-              return NULL;
+-
+-      pt = kzalloc(size, GFP_KERNEL);
++      pt = kzalloc(sizeof(*pt), GFP_KERNEL);
+       if (!pt)
+               return NULL;
+@@ -312,7 +308,7 @@ static long sw_sync_ioctl_create_fence(s
+               goto err;
+       }
+-      pt = sync_pt_create(obj, sizeof(*pt), data.value);
++      pt = sync_pt_create(obj, data.value);
+       if (!pt) {
+               err = -ENOMEM;
+               goto err;
diff --git a/queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch b/queue-4.9/dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch
new file mode 100644 (file)
index 0000000..eac669f
--- /dev/null
@@ -0,0 +1,150 @@
+From f1e8c67123cf171e2b0357e885e426328b241d7d Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 29 Jun 2017 22:12:53 +0100
+Subject: dma-buf/sw-sync: Use an rbtree to sort fences in the timeline
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit f1e8c67123cf171e2b0357e885e426328b241d7d upstream.
+
+Reduce the list iteration when incrementing the timeline by storing the
+fences in increasing order.
+
+v2: Prevent spinlock recursion on free during create
+v3: Fixup rebase conflict inside comments that escaped the compiler.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: Sean Paul <seanpaul@chromium.org>
+Cc: Gustavo Padovan <gustavo@padovan.org>
+Reviewed-by: Sean Paul <seanpaul@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170629211253.22766-1-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c    |   49 +++++++++++++++++++++++++++++++++++++------
+ drivers/dma-buf/sync_debug.h |    5 ++++
+ 2 files changed, 48 insertions(+), 6 deletions(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -96,6 +96,7 @@ struct sync_timeline *sync_timeline_crea
+       obj->context = fence_context_alloc(1);
+       strlcpy(obj->name, name, sizeof(obj->name));
++      obj->pt_tree = RB_ROOT;
+       INIT_LIST_HEAD(&obj->pt_list);
+       spin_lock_init(&obj->lock);
+@@ -142,9 +143,13 @@ static void sync_timeline_signal(struct
+       obj->value += inc;
+-      list_for_each_entry_safe(pt, next, &obj->pt_list, link)
+-              if (fence_is_signaled_locked(&pt->base))
+-                      list_del_init(&pt->link);
++      list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
++              if (!fence_is_signaled_locked(&pt->base))
++                      break;
++
++              list_del_init(&pt->link);
++              rb_erase(&pt->node, &obj->pt_tree);
++      }
+       spin_unlock_irq(&obj->lock);
+ }
+@@ -174,8 +179,38 @@ static struct sync_pt *sync_pt_create(st
+       INIT_LIST_HEAD(&pt->link);
+       spin_lock_irq(&obj->lock);
+-      if (!fence_is_signaled_locked(&pt->base))
+-              list_add_tail(&pt->link, &obj->pt_list);
++      if (!fence_is_signaled_locked(&pt->base)) {
++              struct rb_node **p = &obj->pt_tree.rb_node;
++              struct rb_node *parent = NULL;
++
++              while (*p) {
++                      struct sync_pt *other;
++                      int cmp;
++
++                      parent = *p;
++                      other = rb_entry(parent, typeof(*pt), node);
++                      cmp = value - other->base.seqno;
++                      if (cmp > 0) {
++                              p = &parent->rb_right;
++                      } else if (cmp < 0) {
++                              p = &parent->rb_left;
++                      } else {
++                              if (fence_get_rcu(&other->base)) {
++                                      fence_put(&pt->base);
++                                      pt = other;
++                                      goto unlock;
++                              }
++                              p = &parent->rb_left;
++                      }
++              }
++              rb_link_node(&pt->node, parent, p);
++              rb_insert_color(&pt->node, &obj->pt_tree);
++
++              parent = rb_next(&pt->node);
++              list_add_tail(&pt->link,
++                            parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list);
++      }
++unlock:
+       spin_unlock_irq(&obj->lock);
+       return pt;
+@@ -202,8 +237,10 @@ static void timeline_fence_release(struc
+               unsigned long flags;
+               spin_lock_irqsave(fence->lock, flags);
+-              if (!list_empty(&pt->link))
++              if (!list_empty(&pt->link)) {
+                       list_del(&pt->link);
++                      rb_erase(&pt->node, &parent->pt_tree);
++              }
+               spin_unlock_irqrestore(fence->lock, flags);
+       }
+--- a/drivers/dma-buf/sync_debug.h
++++ b/drivers/dma-buf/sync_debug.h
+@@ -14,6 +14,7 @@
+ #define _LINUX_SYNC_H
+ #include <linux/list.h>
++#include <linux/rbtree.h>
+ #include <linux/spinlock.h>
+ #include <linux/fence.h>
+@@ -25,6 +26,7 @@
+  * @kref:             reference count on fence.
+  * @name:             name of the sync_timeline. Useful for debugging
+  * @lock:             lock protecting @pt_list and @value
++ * @pt_tree:          rbtree of active (unsignaled/errored) sync_pts
+  * @pt_list:          list of active (unsignaled/errored) sync_pts
+  * @sync_timeline_list:       membership in global sync_timeline_list
+  */
+@@ -36,6 +38,7 @@ struct sync_timeline {
+       u64                     context;
+       int                     value;
++      struct rb_root          pt_tree;
+       struct list_head        pt_list;
+       spinlock_t              lock;
+@@ -51,10 +54,12 @@ static inline struct sync_timeline *fenc
+  * struct sync_pt - sync_pt object
+  * @base: base fence object
+  * @link: link on the sync timeline's list
++ * @node: node in the sync timeline's tree
+  */
+ struct sync_pt {
+       struct fence base;
+       struct list_head link;
++      struct rb_node node;
+ };
+ #ifdef CONFIG_SW_SYNC
diff --git a/queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch b/queue-4.9/dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch
new file mode 100644 (file)
index 0000000..9046701
--- /dev/null
@@ -0,0 +1,59 @@
+From 3792b7c1a70815fe4e954221c096f9278638fd21 Mon Sep 17 00:00:00 2001
+From: Gustavo Padovan <gustavo.padovan@collabora.com>
+Date: Sat, 29 Jul 2017 12:22:16 -0300
+Subject: dma-buf/sw_sync: clean up list before signaling the fence
+
+From: Gustavo Padovan <gustavo.padovan@collabora.com>
+
+commit 3792b7c1a70815fe4e954221c096f9278638fd21 upstream.
+
+If userspace already dropped its own reference by closing the sw_sync
+fence fd we might end up in a deadlock where
+dma_fence_is_signaled_locked() will trigger the release of the fence and
+thus try to hold the lock to remove the fence from the list.
+
+dma_fence_is_signaled_locked() tries to release/free the fence and hold
+the lock in the process.
+
+We fix that by changing the order operation and clean up the list and
+rb-tree first.
+
+v2: Drop fence get/put dance and manipulate the list first (Chris Wilson)
+
+Cc: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+Link: https://patchwork.freedesktop.org/patch/msgid/20170729152217.8362-2-gustavo@padovan.org
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -213,11 +213,21 @@ static void sync_timeline_signal(struct
+       obj->value += inc;
+       list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
+-              if (!fence_is_signaled_locked(&pt->base))
++              if (!timeline_fence_signaled(&pt->base))
+                       break;
+               list_del_init(&pt->link);
+               rb_erase(&pt->node, &obj->pt_tree);
++
++              /*
++               * A signal callback may release the last reference to this
++               * fence, causing it to be freed. That operation has to be
++               * last to avoid a use after free inside this loop, and must
++               * be after we remove the fence from the timeline in order to
++               * prevent deadlocking on timeline->lock inside
++               * timeline_fence_release().
++               */
++              fence_signal_locked(&pt->base);
+       }
+       spin_unlock_irq(&obj->lock);
diff --git a/queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch b/queue-4.9/dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch
new file mode 100644 (file)
index 0000000..a7f444d
--- /dev/null
@@ -0,0 +1,51 @@
+From ea4d5a270b57fa8d4871f372ca9b97b7697fdfda Mon Sep 17 00:00:00 2001
+From: Dominik Behr <dbehr@chromium.org>
+Date: Thu, 7 Sep 2017 16:02:46 -0300
+Subject: dma-buf/sw_sync: force signal all unsignaled fences on dying timeline
+
+From: Dominik Behr <dbehr@chromium.org>
+
+commit ea4d5a270b57fa8d4871f372ca9b97b7697fdfda upstream.
+
+To avoid hanging userspace components that might have been waiting on the
+active fences of the destroyed timeline we need to signal with error all
+remaining fences on such timeline.
+
+This restore the default behaviour of the Android sw_sync framework, which
+Android still relies on. It was broken on the dma fence conversion a few
+years ago and never fixed.
+
+v2: Do not bother with cleanup do the list (Chris Wilson)
+
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Dominik Behr <dbehr@chromium.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20170907190246.16425-2-gustavo@padovan.org
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -321,8 +321,16 @@ static int sw_sync_debugfs_open(struct i
+ static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
+ {
+       struct sync_timeline *obj = file->private_data;
++      struct sync_pt *pt, *next;
+-      smp_wmb();
++      spin_lock_irq(&obj->lock);
++
++      list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
++              fence_set_error(&pt->base, -ENOENT);
++              fence_signal_locked(&pt->base);
++      }
++
++      spin_unlock_irq(&obj->lock);
+       sync_timeline_put(obj);
+       return 0;
diff --git a/queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch b/queue-4.9/dma-buf-sw_sync-move-timeline_fence_ops-around.patch
new file mode 100644 (file)
index 0000000..ed44edb
--- /dev/null
@@ -0,0 +1,178 @@
+From 150b6a9d7d6fffb95c0a5349960a10569e8218b5 Mon Sep 17 00:00:00 2001
+From: Gustavo Padovan <gustavo.padovan@collabora.com>
+Date: Sat, 29 Jul 2017 12:22:15 -0300
+Subject: dma-buf/sw_sync: move timeline_fence_ops around
+
+From: Gustavo Padovan <gustavo.padovan@collabora.com>
+
+commit 150b6a9d7d6fffb95c0a5349960a10569e8218b5 upstream.
+
+We are going to use timeline_fence_signaled() in a internal function in
+the next commit.
+
+Cc: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+Link: https://patchwork.freedesktop.org/patch/msgid/20170729152217.8362-1-gustavo@padovan.org
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/sw_sync.c |  138 +++++++++++++++++++++++-----------------------
+ 1 file changed, 69 insertions(+), 69 deletions(-)
+
+--- a/drivers/dma-buf/sw_sync.c
++++ b/drivers/dma-buf/sw_sync.c
+@@ -125,6 +125,75 @@ static void sync_timeline_put(struct syn
+       kref_put(&obj->kref, sync_timeline_free);
+ }
++static const char *timeline_fence_get_driver_name(struct fence *fence)
++{
++      return "sw_sync";
++}
++
++static const char *timeline_fence_get_timeline_name(struct fence *fence)
++{
++      struct sync_timeline *parent = fence_parent(fence);
++
++      return parent->name;
++}
++
++static void timeline_fence_release(struct fence *fence)
++{
++      struct sync_pt *pt = fence_to_sync_pt(fence);
++      struct sync_timeline *parent = fence_parent(fence);
++
++      if (!list_empty(&pt->link)) {
++              unsigned long flags;
++
++              spin_lock_irqsave(fence->lock, flags);
++              if (!list_empty(&pt->link)) {
++                      list_del(&pt->link);
++                      rb_erase(&pt->node, &parent->pt_tree);
++              }
++              spin_unlock_irqrestore(fence->lock, flags);
++      }
++
++      sync_timeline_put(parent);
++      fence_free(fence);
++}
++
++static bool timeline_fence_signaled(struct fence *fence)
++{
++      struct sync_timeline *parent = fence_parent(fence);
++
++      return !__fence_is_later(fence->seqno, parent->value);
++}
++
++static bool timeline_fence_enable_signaling(struct fence *fence)
++{
++      return true;
++}
++
++static void timeline_fence_value_str(struct fence *fence,
++                                  char *str, int size)
++{
++      snprintf(str, size, "%d", fence->seqno);
++}
++
++static void timeline_fence_timeline_value_str(struct fence *fence,
++                                           char *str, int size)
++{
++      struct sync_timeline *parent = fence_parent(fence);
++
++      snprintf(str, size, "%d", parent->value);
++}
++
++static const struct fence_ops timeline_fence_ops = {
++      .get_driver_name = timeline_fence_get_driver_name,
++      .get_timeline_name = timeline_fence_get_timeline_name,
++      .enable_signaling = timeline_fence_enable_signaling,
++      .signaled = timeline_fence_signaled,
++      .wait = fence_default_wait,
++      .release = timeline_fence_release,
++      .fence_value_str = timeline_fence_value_str,
++      .timeline_value_str = timeline_fence_timeline_value_str,
++};
++
+ /**
+  * sync_timeline_signal() - signal a status change on a sync_timeline
+  * @obj:      sync_timeline to signal
+@@ -216,75 +285,6 @@ unlock:
+       return pt;
+ }
+-static const char *timeline_fence_get_driver_name(struct fence *fence)
+-{
+-      return "sw_sync";
+-}
+-
+-static const char *timeline_fence_get_timeline_name(struct fence *fence)
+-{
+-      struct sync_timeline *parent = fence_parent(fence);
+-
+-      return parent->name;
+-}
+-
+-static void timeline_fence_release(struct fence *fence)
+-{
+-      struct sync_pt *pt = fence_to_sync_pt(fence);
+-      struct sync_timeline *parent = fence_parent(fence);
+-
+-      if (!list_empty(&pt->link)) {
+-              unsigned long flags;
+-
+-              spin_lock_irqsave(fence->lock, flags);
+-              if (!list_empty(&pt->link)) {
+-                      list_del(&pt->link);
+-                      rb_erase(&pt->node, &parent->pt_tree);
+-              }
+-              spin_unlock_irqrestore(fence->lock, flags);
+-      }
+-
+-      sync_timeline_put(parent);
+-      fence_free(fence);
+-}
+-
+-static bool timeline_fence_signaled(struct fence *fence)
+-{
+-      struct sync_timeline *parent = fence_parent(fence);
+-
+-      return !__fence_is_later(fence->seqno, parent->value);
+-}
+-
+-static bool timeline_fence_enable_signaling(struct fence *fence)
+-{
+-      return true;
+-}
+-
+-static void timeline_fence_value_str(struct fence *fence,
+-                                  char *str, int size)
+-{
+-      snprintf(str, size, "%d", fence->seqno);
+-}
+-
+-static void timeline_fence_timeline_value_str(struct fence *fence,
+-                                           char *str, int size)
+-{
+-      struct sync_timeline *parent = fence_parent(fence);
+-
+-      snprintf(str, size, "%d", parent->value);
+-}
+-
+-static const struct fence_ops timeline_fence_ops = {
+-      .get_driver_name = timeline_fence_get_driver_name,
+-      .get_timeline_name = timeline_fence_get_timeline_name,
+-      .enable_signaling = timeline_fence_enable_signaling,
+-      .signaled = timeline_fence_signaled,
+-      .wait = fence_default_wait,
+-      .release = timeline_fence_release,
+-      .fence_value_str = timeline_fence_value_str,
+-      .timeline_value_str = timeline_fence_timeline_value_str,
+-};
+-
+ /*
+  * *WARNING*
+  *
diff --git a/queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch b/queue-4.9/dma-fence-clear-fence-status-during-dma_fence_init.patch
new file mode 100644 (file)
index 0000000..39da241
--- /dev/null
@@ -0,0 +1,38 @@
+From 83dd1376fd92f33bdeca9e83d479534a4e7f870b Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 4 Jan 2017 14:12:20 +0000
+Subject: dma-fence: Clear fence->status during dma_fence_init()
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 83dd1376fd92f33bdeca9e83d479534a4e7f870b upstream.
+
+As the fence->status is an optional field that may be set before
+dma_fence_signal() is called to convey that the fence completed with an
+error, we have to ensure that it is always set to zero on initialisation
+so that the typical use (i.e. unset) always flags a successful completion.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Reviewed-by: Sumit Semwal <sumit.semwal@linaro.org>
+Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-1-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/fence.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/dma-buf/fence.c
++++ b/drivers/dma-buf/fence.c
+@@ -526,6 +526,7 @@ fence_init(struct fence *fence, const st
+       fence->context = context;
+       fence->seqno = seqno;
+       fence->flags = 0UL;
++      fence->status = 0;
+       trace_fence_init(fence);
+ }
diff --git a/queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch b/queue-4.9/dma-fence-introduce-drm_fence_set_error-helper.patch
new file mode 100644 (file)
index 0000000..f744731
--- /dev/null
@@ -0,0 +1,119 @@
+From a009e975da5c7d42a7f5eaadc54946eb5f76c9af Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 4 Jan 2017 14:12:22 +0000
+Subject: dma-fence: Introduce drm_fence_set_error() helper
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit a009e975da5c7d42a7f5eaadc54946eb5f76c9af upstream.
+
+The dma_fence.error field (formerly known as dma_fence.status) is an
+optional field that may be set by drivers before calling
+dma_fence_signal(). The field can be used to indicate that the fence was
+completed in err rather than with success, and is visible to other
+consumers of the fence and to userspace via sync_file.
+
+This patch renames the field from status to error so that its meaning is
+hopefully more clear (and distinct from dma_fence_get_status() which is
+a composite between the error state and signal state) and adds a helper
+that validates the preconditions of when it is suitable to adjust the
+error field.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Reviewed-by: Sumit Semwal <sumit.semwal@linaro.org>
+Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-3-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/fence.c |    2 +-
+ include/linux/fence.h   |   30 +++++++++++++++++++++++++-----
+ 2 files changed, 26 insertions(+), 6 deletions(-)
+
+--- a/drivers/dma-buf/fence.c
++++ b/drivers/dma-buf/fence.c
+@@ -551,7 +551,7 @@ fence_init(struct fence *fence, const st
+       fence->context = context;
+       fence->seqno = seqno;
+       fence->flags = 0UL;
+-      fence->status = 0;
++      fence->error = 0;
+       trace_fence_init(fence);
+ }
+--- a/include/linux/fence.h
++++ b/include/linux/fence.h
+@@ -47,7 +47,7 @@ struct fence_cb;
+  * can be compared to decide which fence would be signaled later.
+  * @flags: A mask of FENCE_FLAG_* defined below
+  * @timestamp: Timestamp when the fence was signaled.
+- * @status: Optional, only valid if < 0, must be set before calling
++ * @error: Optional, only valid if < 0, must be set before calling
+  * fence_signal, indicates that the fence has completed with an error.
+  *
+  * the flags member must be manipulated and read using the appropriate
+@@ -79,7 +79,7 @@ struct fence {
+       unsigned seqno;
+       unsigned long flags;
+       ktime_t timestamp;
+-      int status;
++      int error;
+ };
+ enum fence_flag_bits {
+@@ -132,7 +132,7 @@ struct fence_cb {
+  * or some failure occurred that made it impossible to enable
+  * signaling. True indicates successful enabling.
+  *
+- * fence->status may be set in enable_signaling, but only when false is
++ * fence->error may be set in enable_signaling, but only when false is
+  * returned.
+  *
+  * Calling fence_signal before enable_signaling is called allows
+@@ -144,7 +144,7 @@ struct fence_cb {
+  * the second time will be a noop since it was already signaled.
+  *
+  * Notes on signaled:
+- * May set fence->status if returning true.
++ * May set fence->error if returning true.
+  *
+  * Notes on wait:
+  * Must not be NULL, set to fence_default_wait for default implementation.
+@@ -351,13 +351,33 @@ static inline struct fence *fence_later(
+ static inline int fence_get_status_locked(struct fence *fence)
+ {
+       if (fence_is_signaled_locked(fence))
+-              return fence->status < 0 ? fence->status : 1;
++              return fence->error ?: 1;
+       else
+               return 0;
+ }
+ int fence_get_status(struct fence *fence);
++/**
++ * fence_set_error - flag an error condition on the fence
++ * @fence: [in]       the fence
++ * @error: [in]       the error to store
++ *
++ * Drivers can supply an optional error status condition before they signal
++ * the fence, to indicate that the fence was completed due to an error
++ * rather than success. This must be set before signaling (so that the value
++ * is visible before any waiters on the signal callback are woken). This
++ * helper exists to help catching erroneous setting of #fence.error.
++ */
++static inline void fence_set_error(struct fence *fence,
++                                     int error)
++{
++      BUG_ON(test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags));
++      BUG_ON(error >= 0 || error < -MAX_ERRNO);
++
++      fence->error = error;
++}
++
+ signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout);
+ signed long fence_wait_any_timeout(struct fence **fences, uint32_t count,
+                                  bool intr, signed long timeout);
diff --git a/queue-4.9/dma-fence-wrap-querying-the-fence-status.patch b/queue-4.9/dma-fence-wrap-querying-the-fence-status.patch
new file mode 100644 (file)
index 0000000..7615a7e
--- /dev/null
@@ -0,0 +1,163 @@
+From d6c99f4bf093a58d3ab47caaec74b81f18bc4e3f Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 4 Jan 2017 14:12:21 +0000
+Subject: dma-fence: Wrap querying the fence->status
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit d6c99f4bf093a58d3ab47caaec74b81f18bc4e3f upstream.
+
+The fence->status is an optional field that is only valid once the fence
+has been signaled. (Driver may fill the fence->status with an error code
+prior to calling dma_fence_signal().) Given the restriction upon its
+validity, wrap querying of the fence->status into a helper
+dma_fence_get_status().
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Reviewed-by: Sumit Semwal <sumit.semwal@linaro.org>
+Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170104141222.6992-2-chris@chris-wilson.co.uk
+[s/dma_fence/fence/g - gregkh]
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/dma-buf/fence.c      |   25 +++++++++++++++++++++++++
+ drivers/dma-buf/sync_debug.c |   20 ++++++++++----------
+ drivers/dma-buf/sync_file.c  |    6 ++----
+ include/linux/fence.h        |   24 ++++++++++++++++++++++++
+ 4 files changed, 61 insertions(+), 14 deletions(-)
+
+--- a/drivers/dma-buf/fence.c
++++ b/drivers/dma-buf/fence.c
+@@ -281,6 +281,31 @@ int fence_add_callback(struct fence *fen
+ EXPORT_SYMBOL(fence_add_callback);
+ /**
++ * fence_get_status - returns the status upon completion
++ * @fence: [in]       the fence to query
++ *
++ * This wraps fence_get_status_locked() to return the error status
++ * condition on a signaled fence. See fence_get_status_locked() for more
++ * details.
++ *
++ * Returns 0 if the fence has not yet been signaled, 1 if the fence has
++ * been signaled without an error condition, or a negative error code
++ * if the fence has been completed in err.
++ */
++int fence_get_status(struct fence *fence)
++{
++      unsigned long flags;
++      int status;
++
++      spin_lock_irqsave(fence->lock, flags);
++      status = fence_get_status_locked(fence);
++      spin_unlock_irqrestore(fence->lock, flags);
++
++      return status;
++}
++EXPORT_SYMBOL(fence_get_status);
++
++/**
+  * fence_remove_callback - remove a callback from the signaling list
+  * @fence:    [in]    the fence to wait on
+  * @cb:               [in]    the callback to remove
+--- a/drivers/dma-buf/sync_debug.c
++++ b/drivers/dma-buf/sync_debug.c
+@@ -62,29 +62,29 @@ void sync_file_debug_remove(struct sync_
+ static const char *sync_status_str(int status)
+ {
+-      if (status == 0)
+-              return "signaled";
++      if (status < 0)
++              return "error";
+       if (status > 0)
+-              return "active";
++              return "signaled";
+-      return "error";
++      return "active";
+ }
+-static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show)
++static void sync_print_fence(struct seq_file *s,
++                           struct fence *fence, bool show)
+ {
+-      int status = 1;
+       struct sync_timeline *parent = fence_parent(fence);
++      int status;
+-      if (fence_is_signaled_locked(fence))
+-              status = fence->status;
++      status = fence_get_status_locked(fence);
+       seq_printf(s, "  %s%sfence %s",
+                  show ? parent->name : "",
+                  show ? "_" : "",
+                  sync_status_str(status));
+-      if (status <= 0) {
++      if (status) {
+               struct timespec64 ts64 =
+                       ktime_to_timespec64(fence->timestamp);
+@@ -133,7 +133,7 @@ static void sync_print_sync_file(struct
+       int i;
+       seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
+-                 sync_status_str(!fence_is_signaled(sync_file->fence)));
++                 sync_status_str(fence_get_status(sync_file->fence)));
+       if (fence_is_array(sync_file->fence)) {
+               struct fence_array *array = to_fence_array(sync_file->fence);
+--- a/drivers/dma-buf/sync_file.c
++++ b/drivers/dma-buf/sync_file.c
+@@ -377,10 +377,8 @@ static void sync_fill_fence_info(struct
+               sizeof(info->obj_name));
+       strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
+               sizeof(info->driver_name));
+-      if (fence_is_signaled(fence))
+-              info->status = fence->status >= 0 ? 1 : fence->status;
+-      else
+-              info->status = 0;
++
++      info->status = fence_get_status(fence);
+       info->timestamp_ns = ktime_to_ns(fence->timestamp);
+ }
+--- a/include/linux/fence.h
++++ b/include/linux/fence.h
+@@ -334,6 +334,30 @@ static inline struct fence *fence_later(
+               return fence_is_signaled(f2) ? NULL : f2;
+ }
++/**
++ * fence_get_status_locked - returns the status upon completion
++ * @fence: [in]       the fence to query
++ *
++ * Drivers can supply an optional error status condition before they signal
++ * the fence (to indicate whether the fence was completed due to an error
++ * rather than success). The value of the status condition is only valid
++ * if the fence has been signaled, fence_get_status_locked() first checks
++ * the signal state before reporting the error status.
++ *
++ * Returns 0 if the fence has not yet been signaled, 1 if the fence has
++ * been signaled without an error condition, or a negative error code
++ * if the fence has been completed in err.
++ */
++static inline int fence_get_status_locked(struct fence *fence)
++{
++      if (fence_is_signaled_locked(fence))
++              return fence->status < 0 ? fence->status : 1;
++      else
++              return 0;
++}
++
++int fence_get_status(struct fence *fence);
++
+ signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout);
+ signed long fence_wait_any_timeout(struct fence **fences, uint32_t count,
+                                  bool intr, signed long timeout);
index 1256d54eb1ea33b856dc1fb67efae61f01f40fe8..1f5a7faf07a1b1ae35b206fa015172fad46b6261 100644 (file)
@@ -85,3 +85,16 @@ xen-netfront-improve-error-handling-during-initialization.patch
 cec-initiator-should-be-the-same-as-the-destination-for-poll.patch
 xen-netback-vif-counters-from-int-long-to-u64.patch
 net-fec-fix-multicast-filtering-hardware-setup.patch
+dma-buf-dma-fence-extract-__dma_fence_is_later.patch
+dma-buf-sw-sync-fix-the-is-signaled-test-to-handle-u32-wraparound.patch
+dma-buf-sw-sync-prevent-user-overflow-on-timeline-advance.patch
+dma-buf-sw-sync-reduce-irqsave-irqrestore-from-known-context.patch
+dma-buf-sw-sync-sync_pt-is-private-and-of-fixed-size.patch
+dma-buf-sw-sync-fix-locking-around-sync_timeline-lists.patch
+dma-buf-sw-sync-use-an-rbtree-to-sort-fences-in-the-timeline.patch
+dma-buf-sw_sync-move-timeline_fence_ops-around.patch
+dma-buf-sw_sync-clean-up-list-before-signaling-the-fence.patch
+dma-fence-clear-fence-status-during-dma_fence_init.patch
+dma-fence-wrap-querying-the-fence-status.patch
+dma-fence-introduce-drm_fence_set_error-helper.patch
+dma-buf-sw_sync-force-signal-all-unsignaled-fences-on-dying-timeline.patch