summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2019-02-20 20:01:38 -0500
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2019-03-18 11:24:38 -0400
commit9d2230dc1351d54953a94e4ba9b746f8a0408a12 (patch)
tree901d7b322186bbe1a6eab6125e16a5ba9ff02e88
parente482ae9b5fdc01a343f22f52930e85a6cfdf85eb (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.c11
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c31
-rw-r--r--drivers/gpu/drm/drm_writeback.c44
-rw-r--r--include/drm/drm_modeset_helper_vtables.h7
-rw-r--r--include/drm/drm_writeback.h28
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);
2261int drm_atomic_helper_prepare_planes(struct drm_device *dev, 2261int 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
650static struct drm_writeback_job *
651drm_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
662static int drm_atomic_set_writeback_fb_for_connector( 650static 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}
240EXPORT_SYMBOL(drm_writeback_connector_init); 240EXPORT_SYMBOL(drm_writeback_connector_init);
241 241
242int 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
261int 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}
277EXPORT_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
276void drm_writeback_cleanup_job(struct drm_writeback_job *job) 313void 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
51enum mode_set_atomic; 51enum mode_set_atomic;
52struct drm_writeback_connector;
53struct 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
81struct drm_writeback_job { 81struct 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
113static inline struct drm_writeback_connector * 134static 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
146int drm_writeback_set_fb(struct drm_connector_state *conn_state,
147 struct drm_framebuffer *fb);
148
149int drm_writeback_prepare_job(struct drm_writeback_job *job);
150
125void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, 151void 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