diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2019-02-20 20:01:38 -0500 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2019-03-18 11:24:38 -0400 |
commit | 9d2230dc1351d54953a94e4ba9b746f8a0408a12 (patch) | |
tree | 901d7b322186bbe1a6eab6125e16a5ba9ff02e88 | |
parent | e482ae9b5fdc01a343f22f52930e85a6cfdf85eb (diff) |
drm: writeback: Add job prepare and cleanup operations
As writeback jobs contain a framebuffer, drivers may need to prepare and
cleanup them the same way they can prepare and cleanup framebuffers for
planes. Add two new optional connector helper operations,
.prepare_writeback_job() and .cleanup_writeback_job() to support this.
The job prepare operation is called from
drm_atomic_helper_prepare_planes() to avoid a new atomic commit helper
that would need to be called by all drivers not using
drm_atomic_helper_commit(). The job cleanup operation is called from the
existing drm_writeback_cleanup_job() function, invoked both when
destroying the job as part of a aborted commit, or when the job
completes.
The drm_writeback_job structure is extended with a priv field to let
drivers store per-job data, such as mappings related to the writeback
framebuffer.
For internal plumbing reasons the drm_writeback_job structure needs to
store a back-pointer to the drm_writeback_connector. To avoid pushing
too much writeback-specific knowledge to drm_atomic_uapi.c, create a
drm_writeback_set_fb() function, move the writeback job setup code
there, and set the connector backpointer. The prepare_signaling()
function doesn't need to allocate writeback jobs and can ignore
connectors without a job, as it is called after the writeback jobs are
allocated to store framebuffers, and a writeback fence with a
framebuffer is an invalid configuration that gets rejected by the commit
check.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_uapi.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_writeback.c | 44 | ||||
-rw-r--r-- | include/drm/drm_modeset_helper_vtables.h | 7 | ||||
-rw-r--r-- | include/drm/drm_writeback.h | 28 |
5 files changed, 97 insertions, 24 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 40ac19848034..f89641216a44 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -2261,10 +2261,21 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); | |||
2261 | int drm_atomic_helper_prepare_planes(struct drm_device *dev, | 2261 | int drm_atomic_helper_prepare_planes(struct drm_device *dev, |
2262 | struct drm_atomic_state *state) | 2262 | struct drm_atomic_state *state) |
2263 | { | 2263 | { |
2264 | struct drm_connector *connector; | ||
2265 | struct drm_connector_state *new_conn_state; | ||
2264 | struct drm_plane *plane; | 2266 | struct drm_plane *plane; |
2265 | struct drm_plane_state *new_plane_state; | 2267 | struct drm_plane_state *new_plane_state; |
2266 | int ret, i, j; | 2268 | int ret, i, j; |
2267 | 2269 | ||
2270 | for_each_new_connector_in_state(state, connector, new_conn_state, i) { | ||
2271 | if (!new_conn_state->writeback_job) | ||
2272 | continue; | ||
2273 | |||
2274 | ret = drm_writeback_prepare_job(new_conn_state->writeback_job); | ||
2275 | if (ret < 0) | ||
2276 | return ret; | ||
2277 | } | ||
2278 | |||
2268 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { | 2279 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { |
2269 | const struct drm_plane_helper_funcs *funcs; | 2280 | const struct drm_plane_helper_funcs *funcs; |
2270 | 2281 | ||
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 0aabd401d3ca..8fa77def577f 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c | |||
@@ -647,28 +647,15 @@ drm_atomic_plane_get_property(struct drm_plane *plane, | |||
647 | return 0; | 647 | return 0; |
648 | } | 648 | } |
649 | 649 | ||
650 | static struct drm_writeback_job * | ||
651 | drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) | ||
652 | { | ||
653 | WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); | ||
654 | |||
655 | if (!conn_state->writeback_job) | ||
656 | conn_state->writeback_job = | ||
657 | kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); | ||
658 | |||
659 | return conn_state->writeback_job; | ||
660 | } | ||
661 | |||
662 | static int drm_atomic_set_writeback_fb_for_connector( | 650 | static int drm_atomic_set_writeback_fb_for_connector( |
663 | struct drm_connector_state *conn_state, | 651 | struct drm_connector_state *conn_state, |
664 | struct drm_framebuffer *fb) | 652 | struct drm_framebuffer *fb) |
665 | { | 653 | { |
666 | struct drm_writeback_job *job = | 654 | int ret; |
667 | drm_atomic_get_writeback_job(conn_state); | ||
668 | if (!job) | ||
669 | return -ENOMEM; | ||
670 | 655 | ||
671 | drm_framebuffer_assign(&job->fb, fb); | 656 | ret = drm_writeback_set_fb(conn_state, fb); |
657 | if (ret < 0) | ||
658 | return ret; | ||
672 | 659 | ||
673 | if (fb) | 660 | if (fb) |
674 | DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", | 661 | DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", |
@@ -1158,19 +1145,17 @@ static int prepare_signaling(struct drm_device *dev, | |||
1158 | 1145 | ||
1159 | for_each_new_connector_in_state(state, conn, conn_state, i) { | 1146 | for_each_new_connector_in_state(state, conn, conn_state, i) { |
1160 | struct drm_writeback_connector *wb_conn; | 1147 | struct drm_writeback_connector *wb_conn; |
1161 | struct drm_writeback_job *job; | ||
1162 | struct drm_out_fence_state *f; | 1148 | struct drm_out_fence_state *f; |
1163 | struct dma_fence *fence; | 1149 | struct dma_fence *fence; |
1164 | s32 __user *fence_ptr; | 1150 | s32 __user *fence_ptr; |
1165 | 1151 | ||
1152 | if (!conn_state->writeback_job) | ||
1153 | continue; | ||
1154 | |||
1166 | fence_ptr = get_out_fence_for_connector(state, conn); | 1155 | fence_ptr = get_out_fence_for_connector(state, conn); |
1167 | if (!fence_ptr) | 1156 | if (!fence_ptr) |
1168 | continue; | 1157 | continue; |
1169 | 1158 | ||
1170 | job = drm_atomic_get_writeback_job(conn_state); | ||
1171 | if (!job) | ||
1172 | return -ENOMEM; | ||
1173 | |||
1174 | f = krealloc(*fence_state, sizeof(**fence_state) * | 1159 | f = krealloc(*fence_state, sizeof(**fence_state) * |
1175 | (*num_fences + 1), GFP_KERNEL); | 1160 | (*num_fences + 1), GFP_KERNEL); |
1176 | if (!f) | 1161 | if (!f) |
@@ -1192,7 +1177,7 @@ static int prepare_signaling(struct drm_device *dev, | |||
1192 | return ret; | 1177 | return ret; |
1193 | } | 1178 | } |
1194 | 1179 | ||
1195 | job->out_fence = fence; | 1180 | conn_state->writeback_job->out_fence = fence; |
1196 | } | 1181 | } |
1197 | 1182 | ||
1198 | /* | 1183 | /* |
diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 1b497d3530b5..79ac014701c8 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c | |||
@@ -239,6 +239,43 @@ fail: | |||
239 | } | 239 | } |
240 | EXPORT_SYMBOL(drm_writeback_connector_init); | 240 | EXPORT_SYMBOL(drm_writeback_connector_init); |
241 | 241 | ||
242 | int drm_writeback_set_fb(struct drm_connector_state *conn_state, | ||
243 | struct drm_framebuffer *fb) | ||
244 | { | ||
245 | WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); | ||
246 | |||
247 | if (!conn_state->writeback_job) { | ||
248 | conn_state->writeback_job = | ||
249 | kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); | ||
250 | if (!conn_state->writeback_job) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | conn_state->writeback_job->connector = | ||
254 | drm_connector_to_writeback(conn_state->connector); | ||
255 | } | ||
256 | |||
257 | drm_framebuffer_assign(&conn_state->writeback_job->fb, fb); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | int drm_writeback_prepare_job(struct drm_writeback_job *job) | ||
262 | { | ||
263 | struct drm_writeback_connector *connector = job->connector; | ||
264 | const struct drm_connector_helper_funcs *funcs = | ||
265 | connector->base.helper_private; | ||
266 | int ret; | ||
267 | |||
268 | if (funcs->prepare_writeback_job) { | ||
269 | ret = funcs->prepare_writeback_job(connector, job); | ||
270 | if (ret < 0) | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | job->prepared = true; | ||
275 | return 0; | ||
276 | } | ||
277 | EXPORT_SYMBOL(drm_writeback_prepare_job); | ||
278 | |||
242 | /** | 279 | /** |
243 | * drm_writeback_queue_job - Queue a writeback job for later signalling | 280 | * drm_writeback_queue_job - Queue a writeback job for later signalling |
244 | * @wb_connector: The writeback connector to queue a job on | 281 | * @wb_connector: The writeback connector to queue a job on |
@@ -275,6 +312,13 @@ EXPORT_SYMBOL(drm_writeback_queue_job); | |||
275 | 312 | ||
276 | void drm_writeback_cleanup_job(struct drm_writeback_job *job) | 313 | void drm_writeback_cleanup_job(struct drm_writeback_job *job) |
277 | { | 314 | { |
315 | struct drm_writeback_connector *connector = job->connector; | ||
316 | const struct drm_connector_helper_funcs *funcs = | ||
317 | connector->base.helper_private; | ||
318 | |||
319 | if (job->prepared && funcs->cleanup_writeback_job) | ||
320 | funcs->cleanup_writeback_job(connector, job); | ||
321 | |||
278 | if (job->fb) | 322 | if (job->fb) |
279 | drm_framebuffer_put(job->fb); | 323 | drm_framebuffer_put(job->fb); |
280 | 324 | ||
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index cfb7be40bed7..8f3602811eb5 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h | |||
@@ -49,6 +49,8 @@ | |||
49 | */ | 49 | */ |
50 | 50 | ||
51 | enum mode_set_atomic; | 51 | enum mode_set_atomic; |
52 | struct drm_writeback_connector; | ||
53 | struct drm_writeback_job; | ||
52 | 54 | ||
53 | /** | 55 | /** |
54 | * struct drm_crtc_helper_funcs - helper operations for CRTCs | 56 | * struct drm_crtc_helper_funcs - helper operations for CRTCs |
@@ -989,6 +991,11 @@ struct drm_connector_helper_funcs { | |||
989 | */ | 991 | */ |
990 | void (*atomic_commit)(struct drm_connector *connector, | 992 | void (*atomic_commit)(struct drm_connector *connector, |
991 | struct drm_connector_state *state); | 993 | struct drm_connector_state *state); |
994 | |||
995 | int (*prepare_writeback_job)(struct drm_writeback_connector *connector, | ||
996 | struct drm_writeback_job *job); | ||
997 | void (*cleanup_writeback_job)(struct drm_writeback_connector *connector, | ||
998 | struct drm_writeback_job *job); | ||
992 | }; | 999 | }; |
993 | 1000 | ||
994 | /** | 1001 | /** |
diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index 47662c362743..777c14c847f0 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h | |||
@@ -80,6 +80,20 @@ struct drm_writeback_connector { | |||
80 | 80 | ||
81 | struct drm_writeback_job { | 81 | struct drm_writeback_job { |
82 | /** | 82 | /** |
83 | * @connector: | ||
84 | * | ||
85 | * Back-pointer to the writeback connector associated with the job | ||
86 | */ | ||
87 | struct drm_writeback_connector *connector; | ||
88 | |||
89 | /** | ||
90 | * @prepared: | ||
91 | * | ||
92 | * Set when the job has been prepared with drm_writeback_prepare_job() | ||
93 | */ | ||
94 | bool prepared; | ||
95 | |||
96 | /** | ||
83 | * @cleanup_work: | 97 | * @cleanup_work: |
84 | * | 98 | * |
85 | * Used to allow drm_writeback_signal_completion to defer dropping the | 99 | * Used to allow drm_writeback_signal_completion to defer dropping the |
@@ -98,7 +112,7 @@ struct drm_writeback_job { | |||
98 | * @fb: | 112 | * @fb: |
99 | * | 113 | * |
100 | * Framebuffer to be written to by the writeback connector. Do not set | 114 | * Framebuffer to be written to by the writeback connector. Do not set |
101 | * directly, use drm_atomic_set_writeback_fb_for_connector() | 115 | * directly, use drm_writeback_set_fb() |
102 | */ | 116 | */ |
103 | struct drm_framebuffer *fb; | 117 | struct drm_framebuffer *fb; |
104 | 118 | ||
@@ -108,6 +122,13 @@ struct drm_writeback_job { | |||
108 | * Fence which will signal once the writeback has completed | 122 | * Fence which will signal once the writeback has completed |
109 | */ | 123 | */ |
110 | struct dma_fence *out_fence; | 124 | struct dma_fence *out_fence; |
125 | |||
126 | /** | ||
127 | * @priv: | ||
128 | * | ||
129 | * Driver-private data | ||
130 | */ | ||
131 | void *priv; | ||
111 | }; | 132 | }; |
112 | 133 | ||
113 | static inline struct drm_writeback_connector * | 134 | static inline struct drm_writeback_connector * |
@@ -122,6 +143,11 @@ int drm_writeback_connector_init(struct drm_device *dev, | |||
122 | const struct drm_encoder_helper_funcs *enc_helper_funcs, | 143 | const struct drm_encoder_helper_funcs *enc_helper_funcs, |
123 | const u32 *formats, int n_formats); | 144 | const u32 *formats, int n_formats); |
124 | 145 | ||
146 | int drm_writeback_set_fb(struct drm_connector_state *conn_state, | ||
147 | struct drm_framebuffer *fb); | ||
148 | |||
149 | int drm_writeback_prepare_job(struct drm_writeback_job *job); | ||
150 | |||
125 | void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, | 151 | void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, |
126 | struct drm_connector_state *conn_state); | 152 | struct drm_connector_state *conn_state); |
127 | 153 | ||