| .. | .. |
|---|
| 9 | 9 | * of such GNU licence. |
|---|
| 10 | 10 | */ |
|---|
| 11 | 11 | |
|---|
| 12 | +#include <linux/dma-fence.h> |
|---|
| 13 | + |
|---|
| 12 | 14 | #include <drm/drm_crtc.h> |
|---|
| 15 | +#include <drm/drm_device.h> |
|---|
| 16 | +#include <drm/drm_drv.h> |
|---|
| 13 | 17 | #include <drm/drm_modeset_helper_vtables.h> |
|---|
| 14 | 18 | #include <drm/drm_property.h> |
|---|
| 15 | 19 | #include <drm/drm_writeback.h> |
|---|
| 16 | | -#include <drm/drmP.h> |
|---|
| 17 | | -#include <linux/dma-fence.h> |
|---|
| 18 | 20 | |
|---|
| 19 | 21 | /** |
|---|
| 20 | 22 | * DOC: overview |
|---|
| .. | .. |
|---|
| 106 | 108 | .get_driver_name = drm_writeback_fence_get_driver_name, |
|---|
| 107 | 109 | .get_timeline_name = drm_writeback_fence_get_timeline_name, |
|---|
| 108 | 110 | .enable_signaling = drm_writeback_fence_enable_signaling, |
|---|
| 109 | | - .wait = dma_fence_default_wait, |
|---|
| 110 | 111 | }; |
|---|
| 111 | 112 | |
|---|
| 112 | 113 | static int create_writeback_properties(struct drm_device *dev) |
|---|
| .. | .. |
|---|
| 239 | 240 | } |
|---|
| 240 | 241 | EXPORT_SYMBOL(drm_writeback_connector_init); |
|---|
| 241 | 242 | |
|---|
| 243 | +int drm_writeback_set_fb(struct drm_connector_state *conn_state, |
|---|
| 244 | + struct drm_framebuffer *fb) |
|---|
| 245 | +{ |
|---|
| 246 | + WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); |
|---|
| 247 | + |
|---|
| 248 | + if (!conn_state->writeback_job) { |
|---|
| 249 | + conn_state->writeback_job = |
|---|
| 250 | + kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); |
|---|
| 251 | + if (!conn_state->writeback_job) |
|---|
| 252 | + return -ENOMEM; |
|---|
| 253 | + |
|---|
| 254 | + conn_state->writeback_job->connector = |
|---|
| 255 | + drm_connector_to_writeback(conn_state->connector); |
|---|
| 256 | + } |
|---|
| 257 | + |
|---|
| 258 | + drm_framebuffer_assign(&conn_state->writeback_job->fb, fb); |
|---|
| 259 | + return 0; |
|---|
| 260 | +} |
|---|
| 261 | + |
|---|
| 262 | +int drm_writeback_prepare_job(struct drm_writeback_job *job) |
|---|
| 263 | +{ |
|---|
| 264 | + struct drm_writeback_connector *connector = job->connector; |
|---|
| 265 | + const struct drm_connector_helper_funcs *funcs = |
|---|
| 266 | + connector->base.helper_private; |
|---|
| 267 | + int ret; |
|---|
| 268 | + |
|---|
| 269 | + if (funcs->prepare_writeback_job) { |
|---|
| 270 | + ret = funcs->prepare_writeback_job(connector, job); |
|---|
| 271 | + if (ret < 0) |
|---|
| 272 | + return ret; |
|---|
| 273 | + } |
|---|
| 274 | + |
|---|
| 275 | + job->prepared = true; |
|---|
| 276 | + return 0; |
|---|
| 277 | +} |
|---|
| 278 | +EXPORT_SYMBOL(drm_writeback_prepare_job); |
|---|
| 279 | + |
|---|
| 242 | 280 | /** |
|---|
| 243 | 281 | * drm_writeback_queue_job - Queue a writeback job for later signalling |
|---|
| 244 | 282 | * @wb_connector: The writeback connector to queue a job on |
|---|
| 245 | | - * @job: The job to queue |
|---|
| 283 | + * @conn_state: The connector state containing the job to queue |
|---|
| 246 | 284 | * |
|---|
| 247 | | - * This function adds a job to the job_queue for a writeback connector. It |
|---|
| 248 | | - * should be considered to take ownership of the writeback job, and so any other |
|---|
| 249 | | - * references to the job must be cleared after calling this function. |
|---|
| 285 | + * This function adds the job contained in @conn_state to the job_queue for a |
|---|
| 286 | + * writeback connector. It takes ownership of the writeback job and sets the |
|---|
| 287 | + * @conn_state->writeback_job to NULL, and so no access to the job may be |
|---|
| 288 | + * performed by the caller after this function returns. |
|---|
| 250 | 289 | * |
|---|
| 251 | 290 | * Drivers must ensure that for a given writeback connector, jobs are queued in |
|---|
| 252 | 291 | * exactly the same order as they will be completed by the hardware (and |
|---|
| .. | .. |
|---|
| 258 | 297 | * See also: drm_writeback_signal_completion() |
|---|
| 259 | 298 | */ |
|---|
| 260 | 299 | void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, |
|---|
| 261 | | - struct drm_writeback_job *job) |
|---|
| 300 | + struct drm_connector_state *conn_state) |
|---|
| 262 | 301 | { |
|---|
| 302 | + struct drm_writeback_job *job; |
|---|
| 263 | 303 | unsigned long flags; |
|---|
| 304 | + |
|---|
| 305 | + job = conn_state->writeback_job; |
|---|
| 306 | + conn_state->writeback_job = NULL; |
|---|
| 264 | 307 | |
|---|
| 265 | 308 | spin_lock_irqsave(&wb_connector->job_lock, flags); |
|---|
| 266 | 309 | list_add_tail(&job->list_entry, &wb_connector->job_queue); |
|---|
| 267 | 310 | spin_unlock_irqrestore(&wb_connector->job_lock, flags); |
|---|
| 268 | 311 | } |
|---|
| 269 | 312 | EXPORT_SYMBOL(drm_writeback_queue_job); |
|---|
| 313 | + |
|---|
| 314 | +void drm_writeback_cleanup_job(struct drm_writeback_job *job) |
|---|
| 315 | +{ |
|---|
| 316 | + struct drm_writeback_connector *connector = job->connector; |
|---|
| 317 | + const struct drm_connector_helper_funcs *funcs = |
|---|
| 318 | + connector->base.helper_private; |
|---|
| 319 | + |
|---|
| 320 | + if (job->prepared && funcs->cleanup_writeback_job) |
|---|
| 321 | + funcs->cleanup_writeback_job(connector, job); |
|---|
| 322 | + |
|---|
| 323 | + if (job->fb) |
|---|
| 324 | + drm_framebuffer_put(job->fb); |
|---|
| 325 | + |
|---|
| 326 | + if (job->out_fence) |
|---|
| 327 | + dma_fence_put(job->out_fence); |
|---|
| 328 | + |
|---|
| 329 | + kfree(job); |
|---|
| 330 | +} |
|---|
| 331 | +EXPORT_SYMBOL(drm_writeback_cleanup_job); |
|---|
| 270 | 332 | |
|---|
| 271 | 333 | /* |
|---|
| 272 | 334 | * @cleanup_work: deferred cleanup of a writeback job |
|---|
| .. | .. |
|---|
| 280 | 342 | struct drm_writeback_job *job = container_of(work, |
|---|
| 281 | 343 | struct drm_writeback_job, |
|---|
| 282 | 344 | cleanup_work); |
|---|
| 283 | | - drm_framebuffer_put(job->fb); |
|---|
| 284 | | - kfree(job); |
|---|
| 285 | | -} |
|---|
| 286 | 345 | |
|---|
| 346 | + drm_writeback_cleanup_job(job); |
|---|
| 347 | +} |
|---|
| 287 | 348 | |
|---|
| 288 | 349 | /** |
|---|
| 289 | 350 | * drm_writeback_signal_completion - Signal the completion of a writeback job |
|---|
| .. | .. |
|---|
| 307 | 368 | { |
|---|
| 308 | 369 | unsigned long flags; |
|---|
| 309 | 370 | struct drm_writeback_job *job; |
|---|
| 371 | + struct dma_fence *out_fence; |
|---|
| 310 | 372 | |
|---|
| 311 | 373 | spin_lock_irqsave(&wb_connector->job_lock, flags); |
|---|
| 312 | 374 | job = list_first_entry_or_null(&wb_connector->job_queue, |
|---|
| 313 | 375 | struct drm_writeback_job, |
|---|
| 314 | 376 | list_entry); |
|---|
| 315 | | - if (job) { |
|---|
| 377 | + if (job) |
|---|
| 316 | 378 | list_del(&job->list_entry); |
|---|
| 317 | | - if (job->out_fence) { |
|---|
| 318 | | - if (status) |
|---|
| 319 | | - dma_fence_set_error(job->out_fence, status); |
|---|
| 320 | | - dma_fence_signal(job->out_fence); |
|---|
| 321 | | - dma_fence_put(job->out_fence); |
|---|
| 322 | | - } |
|---|
| 323 | | - } |
|---|
| 379 | + |
|---|
| 324 | 380 | spin_unlock_irqrestore(&wb_connector->job_lock, flags); |
|---|
| 325 | 381 | |
|---|
| 326 | 382 | if (WARN_ON(!job)) |
|---|
| 327 | 383 | return; |
|---|
| 328 | 384 | |
|---|
| 385 | + out_fence = job->out_fence; |
|---|
| 386 | + if (out_fence) { |
|---|
| 387 | + if (status) |
|---|
| 388 | + dma_fence_set_error(out_fence, status); |
|---|
| 389 | + dma_fence_signal(out_fence); |
|---|
| 390 | + dma_fence_put(out_fence); |
|---|
| 391 | + job->out_fence = NULL; |
|---|
| 392 | + } |
|---|
| 393 | + |
|---|
| 329 | 394 | INIT_WORK(&job->cleanup_work, cleanup_work); |
|---|
| 330 | 395 | queue_work(system_long_wq, &job->cleanup_work); |
|---|
| 331 | 396 | } |
|---|