diff options
-rw-r--r-- | drivers/dma-buf/dma-fence.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 3 | ||||
-rw-r--r-- | include/linux/dma-fence.h | 24 |
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); | |||
129 | int dma_fence_signal_locked(struct dma_fence *fence) | 129 | int 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 | ||
114 | static void | 114 | static 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 | ||
129 | void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine) | 129 | void 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; | |||
65 | struct dma_fence { | 65 | struct 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; |