diff options
author | Sean Paul <seanpaul@chromium.org> | 2018-02-28 14:19:01 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2018-06-04 12:50:31 -0400 |
commit | 70db18dca4e0130acb0600ad51c33176b6162ccc (patch) | |
tree | 167594fdb755bd979e0359e206a9833060a1b376 | |
parent | e765ea77b0fd51152e07aa4e6850b81552b76da3 (diff) |
drm/msm: Remove msm_commit/worker, use atomic helper commit
Moving further towards switching fully to the the atomic helpers, this
patch removes the hand-rolled worker nonblock commit code and uses the
atomic helpers commit_work model.
Changes in v2:
- Remove commit_destroy()
- Shuffle order of commit_tail calls to further serialize commits
- Use stall in swap_state to avoid abandoned events on disable
Changes in v3:
- Rebased on Archit's private_obj set
Changes in v4:
- None
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/msm_atomic.c | 153 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 4 |
3 files changed, 42 insertions, 116 deletions
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 94f9c3e0e7bf..95c7868445dd 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c | |||
@@ -21,66 +21,6 @@ | |||
21 | #include "msm_gem.h" | 21 | #include "msm_gem.h" |
22 | #include "msm_fence.h" | 22 | #include "msm_fence.h" |
23 | 23 | ||
24 | struct msm_commit { | ||
25 | struct drm_device *dev; | ||
26 | struct drm_atomic_state *state; | ||
27 | struct work_struct work; | ||
28 | uint32_t crtc_mask; | ||
29 | }; | ||
30 | |||
31 | static void commit_worker(struct work_struct *work); | ||
32 | |||
33 | /* block until specified crtcs are no longer pending update, and | ||
34 | * atomically mark them as pending update | ||
35 | */ | ||
36 | static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) | ||
37 | { | ||
38 | int ret; | ||
39 | |||
40 | spin_lock(&priv->pending_crtcs_event.lock); | ||
41 | ret = wait_event_interruptible_locked(priv->pending_crtcs_event, | ||
42 | !(priv->pending_crtcs & crtc_mask)); | ||
43 | if (ret == 0) { | ||
44 | DBG("start: %08x", crtc_mask); | ||
45 | priv->pending_crtcs |= crtc_mask; | ||
46 | } | ||
47 | spin_unlock(&priv->pending_crtcs_event.lock); | ||
48 | |||
49 | return ret; | ||
50 | } | ||
51 | |||
52 | /* clear specified crtcs (no longer pending update) | ||
53 | */ | ||
54 | static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) | ||
55 | { | ||
56 | spin_lock(&priv->pending_crtcs_event.lock); | ||
57 | DBG("end: %08x", crtc_mask); | ||
58 | priv->pending_crtcs &= ~crtc_mask; | ||
59 | wake_up_all_locked(&priv->pending_crtcs_event); | ||
60 | spin_unlock(&priv->pending_crtcs_event.lock); | ||
61 | } | ||
62 | |||
63 | static struct msm_commit *commit_init(struct drm_atomic_state *state) | ||
64 | { | ||
65 | struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); | ||
66 | |||
67 | if (!c) | ||
68 | return NULL; | ||
69 | |||
70 | c->dev = state->dev; | ||
71 | c->state = state; | ||
72 | |||
73 | INIT_WORK(&c->work, commit_worker); | ||
74 | |||
75 | return c; | ||
76 | } | ||
77 | |||
78 | static void commit_destroy(struct msm_commit *c) | ||
79 | { | ||
80 | end_atomic(c->dev->dev_private, c->crtc_mask); | ||
81 | kfree(c); | ||
82 | } | ||
83 | |||
84 | static void msm_atomic_wait_for_commit_done(struct drm_device *dev, | 24 | static void msm_atomic_wait_for_commit_done(struct drm_device *dev, |
85 | struct drm_atomic_state *old_state) | 25 | struct drm_atomic_state *old_state) |
86 | { | 26 | { |
@@ -148,31 +88,37 @@ static void msm_atomic_commit_tail(struct drm_atomic_state *state) | |||
148 | 88 | ||
149 | msm_atomic_wait_for_commit_done(dev, state); | 89 | msm_atomic_wait_for_commit_done(dev, state); |
150 | 90 | ||
151 | drm_atomic_helper_cleanup_planes(dev, state); | ||
152 | |||
153 | kms->funcs->complete_commit(kms, state); | 91 | kms->funcs->complete_commit(kms, state); |
92 | |||
93 | drm_atomic_helper_wait_for_vblanks(dev, state); | ||
94 | |||
95 | drm_atomic_helper_commit_hw_done(state); | ||
96 | |||
97 | drm_atomic_helper_cleanup_planes(dev, state); | ||
154 | } | 98 | } |
155 | 99 | ||
156 | /* The (potentially) asynchronous part of the commit. At this point | 100 | /* The (potentially) asynchronous part of the commit. At this point |
157 | * nothing can fail short of armageddon. | 101 | * nothing can fail short of armageddon. |
158 | */ | 102 | */ |
159 | static void complete_commit(struct msm_commit *c) | 103 | static void commit_tail(struct drm_atomic_state *state) |
160 | { | 104 | { |
161 | struct drm_atomic_state *state = c->state; | 105 | drm_atomic_helper_wait_for_fences(state->dev, state, false); |
162 | struct drm_device *dev = state->dev; | ||
163 | 106 | ||
164 | drm_atomic_helper_wait_for_fences(dev, state, false); | 107 | drm_atomic_helper_wait_for_dependencies(state); |
165 | 108 | ||
166 | msm_atomic_commit_tail(state); | 109 | msm_atomic_commit_tail(state); |
167 | 110 | ||
168 | drm_atomic_state_put(state); | 111 | drm_atomic_helper_commit_cleanup_done(state); |
169 | 112 | ||
170 | commit_destroy(c); | 113 | drm_atomic_state_put(state); |
171 | } | 114 | } |
172 | 115 | ||
173 | static void commit_worker(struct work_struct *work) | 116 | static void commit_work(struct work_struct *work) |
174 | { | 117 | { |
175 | complete_commit(container_of(work, struct msm_commit, work)); | 118 | struct drm_atomic_state *state = container_of(work, |
119 | struct drm_atomic_state, | ||
120 | commit_work); | ||
121 | commit_tail(state); | ||
176 | } | 122 | } |
177 | 123 | ||
178 | /** | 124 | /** |
@@ -191,17 +137,12 @@ int msm_atomic_commit(struct drm_device *dev, | |||
191 | struct drm_atomic_state *state, bool nonblock) | 137 | struct drm_atomic_state *state, bool nonblock) |
192 | { | 138 | { |
193 | struct msm_drm_private *priv = dev->dev_private; | 139 | struct msm_drm_private *priv = dev->dev_private; |
194 | struct msm_commit *c; | ||
195 | struct drm_crtc *crtc; | 140 | struct drm_crtc *crtc; |
196 | struct drm_crtc_state *crtc_state; | 141 | struct drm_crtc_state *crtc_state; |
197 | struct drm_plane *plane; | 142 | struct drm_plane *plane; |
198 | struct drm_plane_state *old_plane_state, *new_plane_state; | 143 | struct drm_plane_state *old_plane_state, *new_plane_state; |
199 | int i, ret; | 144 | int i, ret; |
200 | 145 | ||
201 | ret = drm_atomic_helper_prepare_planes(dev, state); | ||
202 | if (ret) | ||
203 | return ret; | ||
204 | |||
205 | /* | 146 | /* |
206 | * Note that plane->atomic_async_check() should fail if we need | 147 | * Note that plane->atomic_async_check() should fail if we need |
207 | * to re-assign hwpipe or anything that touches global atomic | 148 | * to re-assign hwpipe or anything that touches global atomic |
@@ -209,45 +150,39 @@ int msm_atomic_commit(struct drm_device *dev, | |||
209 | * cases. | 150 | * cases. |
210 | */ | 151 | */ |
211 | if (state->async_update) { | 152 | if (state->async_update) { |
153 | ret = drm_atomic_helper_prepare_planes(dev, state); | ||
154 | if (ret) | ||
155 | return ret; | ||
156 | |||
212 | drm_atomic_helper_async_commit(dev, state); | 157 | drm_atomic_helper_async_commit(dev, state); |
213 | drm_atomic_helper_cleanup_planes(dev, state); | 158 | drm_atomic_helper_cleanup_planes(dev, state); |
214 | return 0; | 159 | return 0; |
215 | } | 160 | } |
216 | 161 | ||
217 | c = commit_init(state); | 162 | ret = drm_atomic_helper_setup_commit(state, nonblock); |
218 | if (!c) { | 163 | if (ret) |
219 | ret = -ENOMEM; | 164 | return ret; |
220 | goto error; | ||
221 | } | ||
222 | 165 | ||
223 | /* | 166 | INIT_WORK(&state->commit_work, commit_work); |
224 | * Figure out what crtcs we have: | ||
225 | */ | ||
226 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) | ||
227 | c->crtc_mask |= drm_crtc_mask(crtc); | ||
228 | 167 | ||
229 | /* | 168 | ret = drm_atomic_helper_prepare_planes(dev, state); |
230 | * Figure out what fence to wait for: | 169 | if (ret) |
231 | */ | 170 | return ret; |
232 | for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { | 171 | |
233 | if ((new_plane_state->fb != old_plane_state->fb) && new_plane_state->fb) { | 172 | if (!nonblock) { |
234 | struct drm_gem_object *obj = msm_framebuffer_bo(new_plane_state->fb, 0); | 173 | ret = drm_atomic_helper_wait_for_fences(dev, state, true); |
235 | struct msm_gem_object *msm_obj = to_msm_bo(obj); | 174 | if (ret) |
236 | struct dma_fence *fence = reservation_object_get_excl_rcu(msm_obj->resv); | 175 | goto error; |
237 | |||
238 | drm_atomic_set_fence_for_plane(new_plane_state, fence); | ||
239 | } | ||
240 | } | 176 | } |
241 | 177 | ||
242 | /* | 178 | /* |
243 | * Wait for pending updates on any of the same crtc's and then | 179 | * This is the point of no return - everything below never fails except |
244 | * mark our set of crtc's as busy: | 180 | * when the hw goes bonghits. Which means we can commit the new state on |
181 | * the software side now. | ||
182 | * | ||
183 | * swap driver private state while still holding state_lock | ||
245 | */ | 184 | */ |
246 | ret = start_atomic(dev->dev_private, c->crtc_mask); | 185 | BUG_ON(drm_atomic_helper_swap_state(state, true) < 0); |
247 | if (ret) | ||
248 | goto err_free; | ||
249 | |||
250 | BUG_ON(drm_atomic_helper_swap_state(state, false) < 0); | ||
251 | 186 | ||
252 | /* | 187 | /* |
253 | * This is the point of no return - everything below never fails except | 188 | * This is the point of no return - everything below never fails except |
@@ -272,17 +207,13 @@ int msm_atomic_commit(struct drm_device *dev, | |||
272 | */ | 207 | */ |
273 | 208 | ||
274 | drm_atomic_state_get(state); | 209 | drm_atomic_state_get(state); |
275 | if (nonblock) { | 210 | if (nonblock) |
276 | queue_work(priv->atomic_wq, &c->work); | 211 | queue_work(system_unbound_wq, &state->commit_work); |
277 | return 0; | 212 | else |
278 | } | 213 | commit_tail(state); |
279 | |||
280 | complete_commit(c); | ||
281 | 214 | ||
282 | return 0; | 215 | return 0; |
283 | 216 | ||
284 | err_free: | ||
285 | kfree(c); | ||
286 | error: | 217 | error: |
287 | drm_atomic_helper_cleanup_planes(dev, state); | 218 | drm_atomic_helper_cleanup_planes(dev, state); |
288 | return ret; | 219 | return ret; |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1c89195da4ff..9cec74c79aa2 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -381,7 +381,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) | |||
381 | 381 | ||
382 | priv->wq = alloc_ordered_workqueue("msm", 0); | 382 | priv->wq = alloc_ordered_workqueue("msm", 0); |
383 | priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); | 383 | priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); |
384 | init_waitqueue_head(&priv->pending_crtcs_event); | ||
385 | 384 | ||
386 | INIT_LIST_HEAD(&priv->inactive_list); | 385 | INIT_LIST_HEAD(&priv->inactive_list); |
387 | INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); | 386 | INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 98e82230b904..2b2688896295 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
@@ -117,10 +117,6 @@ struct msm_drm_private { | |||
117 | struct workqueue_struct *wq; | 117 | struct workqueue_struct *wq; |
118 | struct workqueue_struct *atomic_wq; | 118 | struct workqueue_struct *atomic_wq; |
119 | 119 | ||
120 | /* crtcs pending async atomic updates: */ | ||
121 | uint32_t pending_crtcs; | ||
122 | wait_queue_head_t pending_crtcs_event; | ||
123 | |||
124 | unsigned int num_planes; | 120 | unsigned int num_planes; |
125 | struct drm_plane *planes[16]; | 121 | struct drm_plane *planes[16]; |
126 | 122 | ||