summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma-buf/dma-fence.c16
-rw-r--r--drivers/gpu/drm/i915/gt/intel_breadcrumbs.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c3
-rw-r--r--include/linux/dma-fence.h24
4 files changed, 38 insertions, 18 deletions
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 8a6d0250285d..2c136aee3e79 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -129,6 +129,7 @@ EXPORT_SYMBOL(dma_fence_context_alloc);
129int dma_fence_signal_locked(struct dma_fence *fence) 129int dma_fence_signal_locked(struct dma_fence *fence)
130{ 130{
131 struct dma_fence_cb *cur, *tmp; 131 struct dma_fence_cb *cur, *tmp;
132 struct list_head cb_list;
132 133
133 lockdep_assert_held(fence->lock); 134 lockdep_assert_held(fence->lock);
134 135
@@ -136,16 +137,16 @@ int dma_fence_signal_locked(struct dma_fence *fence)
136 &fence->flags))) 137 &fence->flags)))
137 return -EINVAL; 138 return -EINVAL;
138 139
140 /* Stash the cb_list before replacing it with the timestamp */
141 list_replace(&fence->cb_list, &cb_list);
142
139 fence->timestamp = ktime_get(); 143 fence->timestamp = ktime_get();
140 set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); 144 set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
141 trace_dma_fence_signaled(fence); 145 trace_dma_fence_signaled(fence);
142 146
143 if (!list_empty(&fence->cb_list)) { 147 list_for_each_entry_safe(cur, tmp, &cb_list, node) {
144 list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { 148 INIT_LIST_HEAD(&cur->node);
145 INIT_LIST_HEAD(&cur->node); 149 cur->func(fence, cur);
146 cur->func(fence, cur);
147 }
148 INIT_LIST_HEAD(&fence->cb_list);
149 } 150 }
150 151
151 return 0; 152 return 0;
@@ -231,7 +232,8 @@ void dma_fence_release(struct kref *kref)
231 232
232 trace_dma_fence_destroy(fence); 233 trace_dma_fence_destroy(fence);
233 234
234 if (WARN(!list_empty(&fence->cb_list), 235 if (WARN(!list_empty(&fence->cb_list) &&
236 !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags),
235 "Fence %s:%s:%llx:%llx released with pending signals!\n", 237 "Fence %s:%s:%llx:%llx released with pending signals!\n",
236 fence->ops->get_driver_name(fence), 238 fence->ops->get_driver_name(fence),
237 fence->ops->get_timeline_name(fence), 239 fence->ops->get_timeline_name(fence),
diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
index c092bdf5f0bf..ea56b2cc6095 100644
--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
@@ -112,18 +112,18 @@ __dma_fence_signal__timestamp(struct dma_fence *fence, ktime_t timestamp)
112} 112}
113 113
114static void 114static void
115__dma_fence_signal__notify(struct dma_fence *fence) 115__dma_fence_signal__notify(struct dma_fence *fence,
116 const struct list_head *list)
116{ 117{
117 struct dma_fence_cb *cur, *tmp; 118 struct dma_fence_cb *cur, *tmp;
118 119
119 lockdep_assert_held(fence->lock); 120 lockdep_assert_held(fence->lock);
120 lockdep_assert_irqs_disabled(); 121 lockdep_assert_irqs_disabled();
121 122
122 list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { 123 list_for_each_entry_safe(cur, tmp, list, node) {
123 INIT_LIST_HEAD(&cur->node); 124 INIT_LIST_HEAD(&cur->node);
124 cur->func(fence, cur); 125 cur->func(fence, cur);
125 } 126 }
126 INIT_LIST_HEAD(&fence->cb_list);
127} 127}
128 128
129void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine) 129void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
@@ -185,11 +185,12 @@ void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
185 list_for_each_safe(pos, next, &signal) { 185 list_for_each_safe(pos, next, &signal) {
186 struct i915_request *rq = 186 struct i915_request *rq =
187 list_entry(pos, typeof(*rq), signal_link); 187 list_entry(pos, typeof(*rq), signal_link);
188 188 struct list_head cb_list;
189 __dma_fence_signal__timestamp(&rq->fence, timestamp);
190 189
191 spin_lock(&rq->lock); 190 spin_lock(&rq->lock);
192 __dma_fence_signal__notify(&rq->fence); 191 list_replace(&rq->fence.cb_list, &cb_list);
192 __dma_fence_signal__timestamp(&rq->fence, timestamp);
193 __dma_fence_signal__notify(&rq->fence, &cb_list);
193 spin_unlock(&rq->lock); 194 spin_unlock(&rq->lock);
194 195
195 i915_request_put(rq); 196 i915_request_put(rq);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 301260e23e52..c446eb34d6c6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -184,6 +184,9 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout)
184 184
185 spin_lock(f->lock); 185 spin_lock(f->lock);
186 186
187 if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
188 goto out;
189
187 if (intr && signal_pending(current)) { 190 if (intr && signal_pending(current)) {
188 ret = -ERESTARTSYS; 191 ret = -ERESTARTSYS;
189 goto out; 192 goto out;
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 2ce4d877d33e..3347c54f3a87 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -65,17 +65,31 @@ struct dma_fence_cb;
65struct dma_fence { 65struct dma_fence {
66 spinlock_t *lock; 66 spinlock_t *lock;
67 const struct dma_fence_ops *ops; 67 const struct dma_fence_ops *ops;
68 /* We clear the callback list on kref_put so that by the time we 68 /*
69 * release the fence it is unused. No one should be adding to the cb_list 69 * We clear the callback list on kref_put so that by the time we
70 * that they don't themselves hold a reference for. 70 * release the fence it is unused. No one should be adding to the
71 * cb_list that they don't themselves hold a reference for.
72 *
73 * The lifetime of the timestamp is similarly tied to both the
74 * rcu freelist and the cb_list. The timestamp is only set upon
75 * signaling while simultaneously notifying the cb_list. Ergo, we
76 * only use either the cb_list of timestamp. Upon destruction,
77 * neither are accessible, and so we can use the rcu. This means
78 * that the cb_list is *only* valid until the signal bit is set,
79 * and to read either you *must* hold a reference to the fence,
80 * and not just the rcu_read_lock.
81 *
82 * Listed in chronological order.
71 */ 83 */
72 union { 84 union {
73 struct rcu_head rcu;
74 struct list_head cb_list; 85 struct list_head cb_list;
86 /* @cb_list replaced by @timestamp on dma_fence_signal() */
87 ktime_t timestamp;
88 /* @timestamp replaced by @rcu on dma_fence_release() */
89 struct rcu_head rcu;
75 }; 90 };
76 u64 context; 91 u64 context;
77 u64 seqno; 92 u64 seqno;
78 ktime_t timestamp;
79 unsigned long flags; 93 unsigned long flags;
80 struct kref refcount; 94 struct kref refcount;
81 int error; 95 int error;